线程只能属于一个进程,而进程可以创建多个线程,且最少创建一个主线程
进程是资源分配的基本单位,线程是系统调度的基本单位,线程是真正的执行体
1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于“可运行线程池”中,变得可运行,只等待获取CPU的使用权。即在就绪状态的进程除CPU之外,其它的运行所需资源都已全部获得。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,
调用start()方法来启动一个线程,线程会被放到等待队列,等待CPU调度,并不一定要马上开始执行
join()
就是夹队,暂停其他线程,优先执行此线程,它能够使得t.join()中的t优先执行,当t执行完后才会执行其他线程。能够使得线程之间的并行执行变成串行执行 ,举个例子,如下代码:
public class Mythred implements Runnable {&#64;Overridepublic void run() {for (int i &#61; 0; i < 1000; i&#43;&#43;) {System.out.println("vip插队啦" &#43; i);}}public static void main(String[] args) throws InterruptedException {Thread thread1 &#61; new Thread(new Mythred());thread1.start();for (int i &#61; 0; i < 1000; i&#43;&#43;) {if (i &#61;&#61; 50) thread1.join();System.out.println("普通用户排队中" &#43; i);}}}
起初两个线程并行执行,打印着各自的结果,在主线程执行到50时,thred1调用啦join()方法,暂停啦主线程,
执行完thred1的内容后,才继续执行主线程的内容
stop()
停止线程,不推荐使用
Thread.currentThread().getName()
获取当前线程名字
部分内容摘自 synchronized
synchronized关键字最主要有以下3种应用方式&#xff0c;下面分别介绍
注意锁的必须是同一个对象时才管用,对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁,若是不同对象,岂不就没啦标志的意义?
死锁部分内容摘自 添加链接描述
产生的四个必要条件
产生的原因: 多个线程争夺资源而产生的互相等待的状况
举个例子: 有两个线程,线程1占用啦打印机这个对象锁(其他线程在这个线程释放打印机这个对象锁前是不能获取这个打印机锁的),线程2占用啦电脑锁,现在线程1申请获取线程2的电脑锁,线程2申请获取线程1的打印机锁,结果就导致两个线程在没有拿到自己想要的对象锁前是不会释放自己目前所占有的锁的,然后两者就处于相互等待的状况!
代码演示
public class Ticket implements Runnable {//线程开启标志位,若是1占有ob1的锁,若是2占有ob2的锁int flag;//打印机锁public static Object ob1 &#61; new Object();//电脑锁public static Object ob2 &#61; new Object();&#64;Overridepublic void run() {if (flag &#61;&#61; 1) {synchronized (ob1) {System.out.println(Thread.currentThread().getName() &#43; "目前拥有打印机ob1的锁");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//在未释放ob1锁前申请获取ob2的锁synchronized (ob2) {System.out.println(Thread.currentThread().getName() &#43; "目前拥有打印机ob1和ob2的锁");}}} else {synchronized (ob2) {System.out.println(Thread.currentThread().getName() &#43;"目前拥有打印机ob2的锁");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//在未释放ob2锁前申请获取ob1![在这里插入图片描述](https://img-blog.csdnimg.cn/20200826164702854.png?x-oss-process&#61;image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NjQzMDUx,size_16,color_FFFFFF,t_70#pic_center)
的锁synchronized (ob1) {System.out.println(Thread.currentThread().getName() &#43;"目前拥有打印机ob1和ob2的锁");}}}}//构造函数,初始化线程最初拥有的对象锁public Ticket(int flag) {this.flag &#61; flag;}//现在要模拟的情况是,两个线程争夺对方拥有的对象锁public static void main(String[] args) throws InterruptedException {Ticket ticket1 &#61; new Ticket(1);Ticket ticket2 &#61; new Ticket(2);Thread thread1 &#61; new Thread(ticket1);Thread thread2 &#61; new Thread(ticket2);thread1.start();thread2.start();}}
上述就是发生死锁的过程
解决死锁的办法
通过设置某些限制条件&#xff0c;去破坏产生死锁的四个必要条件中的一个或几个条件&#xff0c;来防止死锁的发生
在资源的动态分配过程中&#xff0c;用某种方法去防止系统进入不安全状态&#xff0c;从而避免死锁的发生
允许系统在运行过程中发生死锁&#xff0c;但可设置检测机构及时检测死锁的发生&#xff0c;并采取适当措施加以清除
当检测出死锁后&#xff0c;便采取适当措施将进程从死锁状态中解脱出来
CAS操作 (CompareAndSwap 系统原语,底层是用汇编实现的)是用汇编编写的一道指令,偏硬件级别 lock cmpxchg, 作用是多个线程操作同一变量时,能保证线程安全,java中关于cas的操作其实也是调用的本地方法
具体操作思路:比如现在,现有一个变量&#xff49;值为0&#xff0c;多个线程想对这个变量进行自增的操作。CAS的具体操作如下&#xff0c;线程1访问变量i的时候&#xff0c;会把变量i的初始值&#xff0c;存在另一个变量e中&#xff0c;之后线程1再进行i自增的操作&#xff0c;此时&#xff0c;i的新值应该是1&#xff0c;但这个这时候不着急把新值赋给i,而是先再将e的值与i当前的值进行比较(因为其他线程有可能在此时更改啦i的值,也就是说i本身的值是有随时有可能变化的,你不能把前一秒i的值自加吧 )&#xff0c;进行比较&#xff0c;如果相等,则说明此时i的值未经其他线程的变更,是准确无误的值,可以放心的把新值赋给i,若不相等,说明此时有线程动过这个值,那怎么办,回炉重新走遍这个流程! 那么在这无限回炉重复的过程也就是自旋操作!
具体思路
无锁–>>偏向锁->>自旋锁(轻量级锁)->>重量级锁
最开始,当线程没有获取锁对象时,处于无锁状态,当只有一个线程(没有竞争),当此线程获取对象锁时,升级为偏向锁
当超过1个线程发生竞争对象锁时,此时便自动升级为自旋锁(轻量级锁)
当线程数较多,且自旋次数超过10次时,便升级为重量级锁
就是两个线程&#xff0c;一个生产者当没货啦则负责生产&#xff0c;产完后等待&#xff0c;当有货时就唤醒生产者&#xff1b;&#xff1b;一个消费者当有货啦则负责消费&#xff0c;消费后就等待&#xff0c;当没货时就唤醒生产者&#xff1b;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Test {static int baozi &#61; 0;static Lock lock &#61; new ReentrantLock();public static void main(String[] args) {new Thread(new Producer()).start();new Thread(new Customer()).start();}static class Producer implements Runnable {&#64;Overridepublic void run() {while (true) {synchronized (lock) {if (baozi &#61;&#61; 0) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}baozi&#43;&#43;;System.out.println("生产完后当前包子数目&#xff1a;" &#43; baozi);lock.notify();} else {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}}static class Customer implements Runnable {&#64;Overridepublic void run() {while (true) {synchronized (lock) {if (baozi !&#61; 0) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}baozi--;System.out.println("消费完后当前包子数目&#xff1a;" &#43; baozi);lock.notify();} else {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}}}
}
单例模式
最最基础的单例模式手写&#xff0c;死也呆给记住&#xff1b;
public class SingleExample {private static volatile SingleExample example;public static synchronized SingleExample getExample() {if (example &#61;&#61; null) {synchronized (SingleExample.class) {if (example &#61;&#61; null) {example &#61; new SingleExample();}}}return example;}public static void main(String[] args) {System.out.println(SingleExample.getExample());}
}