携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第24天,点击查看活动详情
01.多线程介绍
-
1).什么是"进程":"进程"是操作系统中的概念,是指一个独立的应用程序。这个程序运行后由操作系统管理,分配运行所需内存空间,分配CPU时间,等等其他资源。简单的说:一个应用程序对于操作系统来说就是一个进程。
-
2).什么是"多进程":是指操作系统可以同时维护多个应用程序运行,并同一管理这些应用程序,为这些应用程序分配内存,CPU时间等资源。
-
3).多进程的好处:用户可以"同时"运行多个程序,提高用户体验度。同时也会提高硬件的使用率。
-
4).什么是"线程":线程是由一个进程产生的,它是一段独立的代码块,它与主进程"并行"运行,同时抢占系统资源。
-
5).什么是"多线程":一个程序可以产生多个线程,它们之间,以及它们与主进程之间都是"并行"运行,同时抢占系统资源。这种程序就叫多线程程序。也就是一个程序可以"同时"做多件事情。可以提高程序的运行效率。
-
6).什么是"并行":是指多个线程在某个时间段内,同时运行。 什么是"并发":尤其是指多个线程同时抢占一个资源时,这时这个资源受到了"并发"访问。
02.Java多线程原理
-
1).分时调度:为每个程序平均分配CPU时间,轮流执行。
-
2).抢占式调度:系统会根据每个线程"优先级"来决定怎样选择执行的线程,优先级高的线程,会有一定的几率被优先执行。
Java是"抢占式"调度,可以设置线程的"优先级",一共十个级别,从低到高:1--10级,默认5级。
03.主线程
Java程序从main()开始运行,运行后,JVM就是"主进程",main()方法是作为一个独立的线程运行的,所以main()就是一个主线程。
04.实现线程的方式1_继承Thread类
1).自定义线程类,继承自Thread。
2).重写run()方法;
3).启动线程:
1).创建自定义线程类的对象;
2).调用线程对象的start()方法启动线程。
注意:
1).run()方法中:在普通方法中做的事情,在run()方法中都可以做,例如:定义变量,if语句,循环语句,调用其它方法.....主要编写的是在线程中需要做的事情。
2).在线程类中,重写的run()方法,但启动线程调用的是start()方法。
//伪代码:
class Thread{
public void start(){
run();
}
public void run(){
System.out.println("a");
}
}
class MyThread extends Thread{
public void run(){
System.out.println("b");
}
}
main(){
MyThread t = new MyThread();
t.start();
}
3).对于一个"线程对象",不能多次的调用start():
MyThread t = new MyThread();
t.start();
....
t.start();//编译通过,但运行时异常。
4).对于一个"线程类",可以创建多个"线程对象",每个线程对象都可以作为一个独立的 线程运行:
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.start();//OK的
t2.start();//OK的
t3.start();//OK的
05.Thread类的常用方法
1).public static void sleep(long millis):让当前线程暂停millis毫秒
2).public final String getName():获取线程名称
每个线程都有一个默认的名字:Thread-[索引]
3).public final void setName(String name):设置线程名称
4).public static Thread currentThread() : 可以获取当前正在执行的"线程对象"
5).public void interrupt() : 中断线程
注意:只有在run()方法中处于:Thread的sleep()状态时,才会促使run()抛出异常,在处理异常的位置,终止执行。
06.实现线程的方式2_实现Runnable接口
1).自定义类实现Runnable接口
2).重写run()方法;
3).启动线程:
1).创建一个Thread对象,并将自定义Runnable的对象作为参数传给Thread的构造方法;
2).调用Thread对象的start()方法启动线程
两种方式的选择:
1).第一种的实现方式:子类继承Thread
2).第二种的实现方式:子类实现Runnable接口,对于子类灵活了很多。
07.线程的匿名内部类的使用
1).new Thread(){匿名的Thread子类}.start(); 例如:
new Thread(){
public void run(){
for(int i = 0;i < 1000 ; i++){
System.out.println("i = " + i);
}
}
}.start();
for(int k = 0; k < 1000 ; k++){
System.out.println("k = " + k):
}
2).new Thread(匿名的Runnable子类).start(); 例如:
new Thread(new Runnable(){
public void run(){
for(int i = 0;i < 1000 ; i++){
System.out.printl("i = " + i);
}
}
}).start();
for(int k = 0; k < 1000 ; k++){
System.out.println("k = " + k):
}
08.多线程的安全性问题
多线程安全性问题产生的原因:
-
1).多个线程并发的访问同一个共享资源时;
-
2).处理共享资源的代码不具有"原子性";
09.解决多线程的安全性问题_线程同步
1).在"共享资源"处,使用"同步方法":
class Tickets{
private static int tickets = 100;
//共享资源
public synchronized static int getTicket(){
//被同步的方法,一个线程进入后,会锁住此方法,其它线程在外面排队
//此线程执行完毕,会释放锁,下一个线程才会进来
}
}
2).同步的方式:
1).同步方法【常用】
public synchronized void show(){
}
2).同步代码块:
public void show(){
synchronzied(this){
}
...
synchronized(this){
}
...
synchronized(this){
}
...
}
说明:
synchronized(锁对象--一般使用this){//在用于普通方法内时,一般使用this
}
锁对象:作用:保证多个线程共用同一把锁,就可以实现同步。
3).Lock锁:
1).JDK5之后出现的一个新的锁,它提供了比synchronized更灵活的锁。
2).使用方式:
Lock l = ...;
l.lock();//加锁
try {
// 同步代码
} finally {
l.unlock();//解锁
}
10.关于StringBuffere和StringBuilder
1).StringBuffer:线程安全的,效率低;内部全部都是"同步方法"
2).StringBuilder:线程不安全的,效率高;
11.线程的状态图
1).新建-->就绪-->运行-->死亡
2).新建-->就绪-->运行-->就绪-->运行-->死亡
3).新建-->就绪-->运行-->阻塞-->就绪-->运行-->死亡