线程基础
1.线程相关概念:
程序(program):代码
进程:是指运行中的程序,进程是程序的一次执行过程,或是正在运行的一个程序,是动态过程,有自身的产生、存在和消亡的过程,进程在运行时会占用内存空间
线程:线程由进程创建的,是进程的一个实体,一个进程可以有多个线程
1.创建线程的两种方式
1.继承Thread类,重写run方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class work1 { public static void main(String[]args) throws InterruptedException{ cat c1 = new cat(); c1.start(); System.out.println("主线程继续执行"+Thread.currentThread().getName()); for(int i = 0;i<60;i++) { System.out.println("主线程 i=" + i); Thread.sleep(1000); } } } class cat extends Thread{ public void run() { int times = 0; while(true) { if(times == 3) { break; } System.out.println("喵喵,我是小猫咪"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } times++; } } }
|
2.实现Runnable接口,重写run方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
|
public class work2 { public static void main(String[]args) { dog d1 = new dog(); Thread t1 = new Thread(d1); t1.start(); } } class dog implements Runnable{ int count = 0; public void run() { while(true) { System.out.println("小狗叫"+(++count)+ Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if(count == 10) { break; } } } }
public class work3 { public static void main(String []args) { t3 t = new t3(); t4 t2 = new t4(); Thread th1 = new Thread(t); Thread th2 = new Thread(t2); th1.start(); th2.start(); } } class t3 implements Runnable{ int n = 0; public void run() { while(true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } n++; System.out.println("hei"+n); if(n ==10) { break; } } } } class t4 implements Runnable{ int n = 0; public void run() { while(true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } n++; System.out.println("hello"+n); if(n == 10) { break; } } } }
|
3.实现Runnable接口方式更加适合多个线程共享一个资源的情况,也避免了单继承的限制,建议使用Runnable
4.线程终止
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
public class work4 { public static void main(String[]args) throws InterruptedException { thread th = new thread(); Thread t1 = new Thread(th); t1.start(); System.out.println("main程正在运行"); Thread.sleep(10*1000); th.setLoop(false); } } class thread implements Runnable{ boolean loop = true; int count = 0; public void run() { while(loop) { try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("运行中"+(++count)); } } public void setLoop(boolean loop) { this.loop=loop; } }
|
2.线程插队
t1.join() //等待某线程结束,再恢复当前线程的运行
t1.yield() //让出CPU资源,当前线程进入就绪状态
注意: yield()是让出资源,但并不放弃。它会进入就绪状态,也就是说:它还会与其他线程一起抢占资源,所以yield()的线程,仍然有可能再次抢占资源。在加上线程运行的不确定性,所以会导致上面的结论并不是绝对的,只是出现的概率要高一些。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class work5 { public static void main(String[]args) throws InterruptedException { T t = new T(); Thread t1 = new Thread(t); for(int i = 1;i<=10;i++) { System.out.println("hi"+i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if(i==5) { t1.start(); t1.join(); } } } } class T implements Runnable{ public void run() { for(int i = 1;i<=10;i++) { System.out.println("hello"+ i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
|
3.线程优先级
1.Java线程有优先级,优先级高的线程会获得较多的CPU运行机会。
2.Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。
Java线程的优先级用整数表示,取值范围是1~10; 10最高级。
3.每个线程都有默认的优先级。主线程的默认优先级为Thread.NORM_PRIORITY(5)
4.守护线程
守护线程:一般是为工作线程服务的,当所有用户线程结束,守护线程自动结束,常见的守护进程是垃圾回收机制
如果我们希望当前main线程结束后,子线程自动结束,我们只需要将子线程设置成守护线程即可:xxx.setDaemon(true);该语句要放在xxx.start();语句前
5.线程的生命周期
1.NEW //尚未启动的线程处于此状态
2.RUNNABLE //在java虚拟机中执行的线程处于此状态
3.BLOCKED //被阻塞等待监视器锁定的线程处于此状态
4.WAITING //正在等待另一个线程执行特定动作的线程处于此状态
5.TIMED_WAITING //正待等待另一个线程执行达到指定等待时间的线程处于此状态
6.TERMINATED //已退出的线程处于此状态
6.线程同步
1.在多线程编程,一些敏感数据不允许被多个线程访问,此时就使用同步访问技术,保证数据在任何时刻最多一个线程访问
2.可以理解为当一个线程在对内存操作时,不允许其他线程操作内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| synchronized(对象){ }
public synchronized void m(String name){ }
public class work6 { public static void main(String[]args) { SellTicket03 s03 = new SellTicket03(); Thread t1 = new Thread(s03); Thread t2 = new Thread(s03); Thread t3 = new Thread(s03); t1.start(); t2.start(); t3.start(); } } class SellTicket03 implements Runnable{ private int ticketNum=100; private boolean loop = true; public synchronized void sell() { if(ticketNum <=0) { System.out.println("售票结束"); loop = false; return; } try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("窗口"+Thread.currentThread().getName()+"售出一张票"+ "剩余票数"+(--ticketNum)); } public void run() { while(loop) { sell(); } } }
|
7.线程锁
1.线程同步会导致会出现线程锁导致程序卡死在某一个地方无法继续执行
下面操作会释放锁
1.当前线程的同步方法、同步代码块执行结束
2.当前线程在同步代码块,同步方法中遇到break、return
3.当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致一场结束
4.当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁
下面操作不会释放锁
1.线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行,不会释放锁
2.线程执行同步代码块时,其他线程调用了该线程的suspend()方法将线程挂起,该线程不会释放锁,避免使用suspen()和resume()来控制线程