一、启动多线程的三种方式
(资料图)
1、继承Thread 接口类 实现 run() 方法
static class MyThred extends Thread{ @Override public void run(){system.out.println("Hellow MyThread!"))}}
2、继承Runnable 接口类 实现 run() 方法
static class MyThred extends Runnable{ @Override public void run(){system.out.println("Hellow Run!"))}}
3、通过线程池也可以启动一起线程
Executors.newCachedThread
二、线程的 Sleep_Yield_Join基本 方法
1、Sleep()
1、Thread.sleep(500);
概念:CPU没有线程概念,当前线程在这休息500毫秒,这段时间其他线程去运行。运行完后再接着回来运行
2、Yield()
Thread.yield();
概念:运行过程中,yield() 一下,本质上是让出一下cpu,返回 “就绪” 状态,其他线程能不能抢到不管。
3、Join()
Thread t1=new Thread(()->{ for(int i=0;i<100;i++) { System.out.println("A"+i); try{ Thread.sleep(500); }catch(InterrupedException e){ e.printStackTrace(); } }});Thread t2=new Thread(()->{ try{ t1.join(); }catch(InterrupedException e){ e.printStackTrace(); }});
概念:当运行t2线程的时候调用一下t1线程,当t1线程完成以后,回来接着调用t2线程。
三、线程的状态
1、java里的线程状态迁移图,都是通过JVM来管理的,通过操作系统被管理。,通过线程的getState()获取状态。
1、NEW 状态:创建了,未调用初始状态。
2、Runnable 状态:交给操作系统执行(线程调度器)
2.1、Ready:就绪状态,在CPU的等待队列里,排着队,还没运行呢,
2.2、Running:正在运行的状态,正在CPU里运行中。
3、Teminated 状态:运行结束。
4、TimedWaiting:等待状态,Thread.sleep(time),o.wait(time),t.join(time),LockSupport.parkNanos(),LockSupport.partUntill(),会进入这个状态。
5、Waitig:等待状态,o.wait(), t.join() ,LockSupport.part(),会进去这个状态
6、Blocked:阻塞状态;进入到同步代码块,没有得到锁的时候。
四、高并发、sysnchronized 关键字
1、多个线程访问一个资源的时候,对这个资源加锁
private int count=10;private Object o=new Object();public void m(){ synchronized(o){//任何线程要想执行以下代码,必须先拿到o的锁 count--; System.out.println(Thread.currentThread().getName()+"count="+count); }}
每次new一个object很麻烦,可以锁当前对象 this
private int count=10;public void m(){ synchronized(this){ count--; System.out.println(Thread.currentThread().getName()+"count="+count); }}
可以简写成以下代码,一个 synchronized 方法
private int count=10;public synchronized void m(){//任何线程要想执行以下代码,必须先拿到o的锁 count--; System.out.println(Thread.currentThread().getName()+"count="+count);}
静态方法也可以
private int count=10;public synchronized static void m(){//这里等同于synchronized(T.class) count--; System.out.println(Thread.currentThread().getName()+"count="+count);}public static void mm(){ synchronized(T.class){ count--; }}
五、synchronized的底层实现
1、JDK早期 synchronized 是重量级的,要向系统申请锁,很慢。
2、后来JDK(1.5)改进,锁升级,原来都是找操作系统申请锁,到后期对synchronized 做了一些改进,效率高不少。
例如:synchronized(object)的时候,只有一个线程访问,是不给他加锁的,只记录线程ID(偏向锁)。如果有线程争用,就升级为(自旋锁),自旋锁 如果一个线程 旋了 10次以后 还没得到锁,则升级为(系统锁)操作系统锁。
3、只能升级锁,不能降级,例如多个线程通过争用升级到(系统锁),线程数下去以后,不会降级!!!
5、加锁代码执行时间长的情况下,线程数比较多,使用系统锁(系统锁),加锁代码执行时间短,线程数少的情况下,使用(自旋锁)。
六、使用synchronized注意
1、不能使用String常量、Integer、Long 等基础数据类型。
2、synchronized 锁不住空对象,空对象没有markword。