线程 Thread
- 进程与线程
- 进程:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
- 线程:线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
- 线程的实现
继承Thread类
1 Thread t = new T1(); 2 t.start(); 3 Thread t1 = new T1(); 4 t1.start(); 5 System.out.println(Thread.currentThread().getName());
join() 和 yield()
join:A.join()等待A线程,让A先执行
yield:礼让
1 //Thread类 2 //继承 3 class T1 extends Thread{ 4 5 Thread t; 6 @Override 7 public void run() { 8 // 线程里面需要执行的内容 9 for(int i = 1 ; i <= 100 ; i++) { 10 if( i == 50 ) { 11 try { 12 if(t!=null) { 13 t.join(1);//join是插队,里面的数字代表插队多少毫秒,过了这个时间之后就继续抢占 14 } 15 } catch (InterruptedException e) { 16 // TODO Auto-generated catch block 17 e.printStackTrace(); 18 } 19 Thread.yield();//如果执行到50,就礼让一下 20 } 21 System.out.println(Thread.currentThread().getName() + "----------" + i); 22 } 23 } 24 }
yeild的主函数
1 T1 t1 = new T1();
2 T1 t2 = new T1();
3 t1.t = t2;
4 t2.t = null;
5 t1.start();
6 t2.start();
实现Runnable接口
Runnable和Thread的区别
1 //Runnable和Thread的区别就是Runnable里的资源可以让别人共享 2 //r1线程的资源可以向两条线程里面共享 3 Runnable r1 = new R1(); 4 Thread t1 = new Thread(r1); 5 Thread t2 = new Thread(r1); 6 t1.start(); 7 t2.start(); 8 Thread.sleep(10);//main函数调用别的线程的时候,自己不会停止,有可能另一个线程还没执行完,输出会什么都没有 9 System.out.println(((R1)r1).strB);
1 class R1 implements Runnable{ 2 StringBuilder strB = new StringBuilder(); 3 @Override 4 public void run() { 5 for(int i = 1 ; i < 10 ; i++) { 6 strB.append(i); 7 //在这里不可以throws只能try catch,因为Runnable里面的run没有throws 8 //只能更精确,不能更宽泛 9 try { 10 Thread.sleep(1); 11 } catch (InterruptedException e) { 12 e.printStackTrace(); 13 } 14 } 15 } 16 }
平常使用Runnable最好
- 线程的常用方法
- 线程的生命周期
线程的五状态图
包括 : 新建(new) 就绪(runnable) 运行(running) 堵塞(blocked) 死亡(dead)
- 线程安全
线程安全就是说多线程访问同一代码,不会产生不确定的结果。
- 在多线程环境中,当各线程不共享数据的时候,即都是私有(private)成员,那么一定是线程安全的。 但这种情况并不多见,在多数情况下需要共享数据,这时就需要进行适当的同步控制了。
- 线程安全一般都涉及到synchronized, 就是一段代码同时只能有一个线程来操作 不然中间过程可能会 产生不可预制的结果。
- 如果代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运 行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
- 关键字synchronized
当两个并发线程访问同一个对象object中的synchronized(this)同步代码块时,一段时间内只能有一个线程被执行,另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
代码:
同步方法:
- 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象
- 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象
同步代码块:
- 被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
注意:
- 同步代码块中出现异常,锁自动释放
- 同步不能继承,所以还得在子类的方法中添加synchronized关键字
- 当一个线程访问object的一个synchronized同步代码块时,另一个线程仍然可以访问该object对象中的非synchronized(this)同步代码块。
- 在使用同步synchronized(this)代码块时需要注意的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对同一个object中所有其他synchronized(this)同步代码块的访问将被阻塞,这说明synchronized使用的“对象监视器”是一个synchronized方法一样,synchronized(this)代码块也是锁定当前对象的
- 多个线程调用同一个对象中的不同名称的synchronized同步方法或synchronized(this)同步代码块时,调用的效果就是按顺序执行,也就是同步的,阻塞的。
- 锁对象可以是任意对象
- 关键字synchronized还可以应用在static静态方法上,如果这样写,那是对当前的*.java文件对应的Class类进行持锁。
- 异步的原因是持有不同的锁,一个是对象锁,另外一个是Class锁,而Class锁可以对类的所有对象实例起作用。
- 将synchronized(string)同步块与String联合使用时,要注意常量池以带来的一些例外(尽量避免)
1 package day12; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class _Thread_P2 { 7 public static void main(String[] args) throws InterruptedException { 8 Runnable r = new T(); 9 10 Thread t1 = new Thread(r); 11 Thread t2 = new Thread(r); 12 Thread t3 = new Thread(r); 13 Thread t4 = new Thread(r); 14 Thread t5 = new Thread(r); 15 Thread t6 = new Thread(r); 16 Thread t7 = new Thread(r); 17 Thread t8 = new Thread(r); 18 t1.start(); 19 t2.start(); 20 t3.start(); 21 t4.start(); 22 t5.start(); 23 t6.start(); 24 t7.start(); 25 t8.start(); 26 while(t1.isAlive() || t2.isAlive() || t3.isAlive() || t4.isAlive()) { 27 28 } 29 Thread.sleep(1000); 30 System.out.println(T.l.size()); 31 } 32 } 33 34 class T implements Runnable{ 35 36 static List l = new ArrayList(); 37 38 @Override 39 public void run() { 40 for(int i = 0 ; i < 100 ; i++) { 41 test(i); 42 } 43 } 44 //锁--对象(方法上锁对象是this) 45 public synchronized void test(int i) { 46 l.add(i); 47 } 48 }
1 package day12; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class _Lock { 7 public static void main(String[] args) throws InterruptedException { 8 Object obj = new Object(); 9 //是同步的,因为锁都是同一个obj对象 10 Thread t1 = new Test(obj); 11 Thread t2 = new Test(obj); 12 Thread t3 = new Test(obj); 13 Thread t4 = new Test(obj); 14 15 //不是同步的,因为每个都传的是一个新的obj 16 // Thread t1 = new Test(new Object()); 17 // Thread t2 = new Test(new Object()); 18 // Thread t3 = new Test(new Object()); 19 // Thread t4 = new Test(new Object()); 20 t1.start(); 21 t2.start(); 22 t3.start(); 23 t4.start(); 24 Thread.sleep(1000); 25 System.out.println(Test.list.size()); 26 } 27 } 28 29 class Test extends Thread{ 30 Object obj; 31 public Test(Object obj) { 32 this.obj = obj; 33 } 34 static List list = new ArrayList(); 35 public void run() { 36 for(int i = 0 ; i < 100 ; i++) { 37 add(i); 38 } 39 } 40 41 public void add(int i) { 42 //(锁对象) 43 //同步必须传入的是一个Object,不能是一个int或者什么的 44 synchronized (obj) { 45 list.add(i); 46 } 47 } 48 }
输出的是 : 400
因为同步了