1. 守护线程
1.1 守护线程是什么
守护线程 (Daemon) 是在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件
1.2 守护线程的作用
守护线程在并发编程中扮演着重要的角色,它们的主要作用是为其他前台线程的运行提供便利服务。这些服务可能包括但不限于垃圾回收 后台任务执行等。守护线程的特点是:它们是在后台运行的,并且仅在普通 非守护线程仍然运行时才需要。
守护线程在主执行完毕的时候,守护线程自动结束,如果主线程不结束,那么守护线程将会一直运行
1.3 守护线程的实现
例:
public class Shohu extends Thread{
public void run(){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("守护线程");
}
}
public class MyTest {
public static void main(String[] args) {
Shohu shohu = new Shohu();//现成的实例
shohu.setDaemon(true);//设置成为守护线程
//守护的线程是 main(主线程)
shohu.start();
try {
Thread.sleep(5000);//在这五秒之内 守护线程 需要工作
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("--------");// 主线程结束
}
}
因为主线程里面的内容简单 怕看不出来效果 因此鼠鼠在主线程中添加了一个 sleep() 方法
运行以上代码后的结果:
运行中出现 守护线程 后会有五秒的停顿
2. Wait()方法
2.1 Wait() 方法
Wait() 方法是 Object 类的方法,使用时必须存放在同步代码块(synchronized)中,他的作用是使当前执行 Wait() 方法的线程等待,在 Wait() 所在的代码行处暂停执行,并释放锁,直到接到通知或中断。在调用 Wait() 方法时可在括号中直接写入等待时间。如: wait(1000) 等待一秒
例:
public class WaitTest {
private static Object object = new Object();
static class Wait extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println("当前线程开始等待:" + this.getName());
//
try {
object.wait(10000);// 10s
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(this.getName() + "等待结束");
}
}
}
}
public class MyTest2 {
public static void main(String[] args) {
WaitTest.Wait wait = new WaitTest.Wait();
wait.setName("wait1");
WaitTest.Wait wait2 = new WaitTest.Wait();
wait2.setName("wait2");
wait.start();
wait2.start();
}
}
运行以上代码后的结果:
2.2 Notify() 方法
Notify() 方法是用来通知那些可能等待该锁的其他线程,如果有多个线程等待,那么唤醒的线程是随机的。
例:
public class WaitTest {
private static Object object = new Object();
static class Wait extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println("当前线程开始等待:" + this.getName());
//
try {
object.wait(10000);// 10s
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(this.getName() + "等待结束");
}
}
}
static class Notify extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println("开始唤醒线程:" + this.getName());
object.notifyAll();
System.out.println("唤醒线程:" + this.getName() + "等待结束");
}
}
}
}
public class MyTest2 {
public static void main(String[] args) {
WaitTest.Wait wait = new WaitTest.Wait();
wait.setName("wait1");
WaitTest.Wait wait2 = new WaitTest.Wait();
wait2.setName("wait2");
wait.start();
wait2.start();
//唤醒线程
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
WaitTest.Notify notify = new WaitTest.Notify();
notify.start();
}
}
运行以上代码后的结果:
2.3 NotifyAll() 方法
NotifyAll() 方法是用来唤醒所有的线程
总结:
1. Wait() 方法可以使线程暂停运行,而 Notify() 方法通知暂停的线程继续运行。
2. Wait() 方法会释放锁,Notify() 方法不会释放锁
3. Wait() 释放锁之后会回来继续执行时,必须先拿到锁,否则不会执行
3. Wait() 方法和 Sleep() 方法
相同点:
1. 都是可以让线程进入休眠
2. 都可以响应 Interrupt (中断) 请求
不相同点:
1. wait 必须配合 synchronized 一起使用,而 sleep 不需要。
2. wait 属于 Object(对象)的方法,而 sleep 属于 Thread(线程)的方法。
3. wait 释放锁,而 sleep 不释放锁。
4. wait 不需要传参,而 sleep 必须要传递一个数值类型参数。
5. 一般情况下,sleep 只能等待超过时间之后再回复执行,而 wait 可以接收 notify/notifyAll之后就执行。
4. Lock
Lock 是一个类似于 synchronized 的线程同步机制。但是 Lock 比 synchronized 更加灵活。Lock 是个接口,有个实现类是 ReentrantLock 。
Lock 必须要用户手动释放锁,如果没有主动释放锁,就有可能导致会出现锁死现象。
例:
public class MyRhradLock implements Runnable {
private int tickect = 10;
@Override
public void run() {//代码块{}
Lock lock = new ReentrantLock();
try {
while (tickect > 0) {
lock.lock();//枷锁
System.out.println(Thread.currentThread().getName() + "卖出去了一张,还剩" + tickect--);
}
} catch (Exception e) {
} finally {
lock.unlock();
}
}
}
public class MyTest2 {
public static void main(String[] args) {
MyRhradLock myRhradLock = new MyRhradLock();
Thread thread = new Thread(myRhradLock,"张三");
Thread thread1 = new Thread(myRhradLock,"张三四");
Thread thread2 = new Thread(myRhradLock,"张三四五");
thread.start();
thread2.start();
thread1.start();
}
}
运行以上代码后的结果:
5. Volatile 关键字
Volatile 关键字的作用主要有两个:
1. 线程的可见性: 当一个线程修改一个共享变量是,另一个线程能读取到这个修改的值.
2. 顺序一致性: 禁止指令重排序。
例:
public class Num {
private volatile int x;
private volatile int y;
//指令重播 x y x==y
public void add(){
System.out.println("开始调用");
x++;
y++;
eq();
System.out.println("调用结束");
}
public void eq(){
System.out.println("x:"+x+"\ty:"+y+"\tx==y:"+(x==y));
}
public static void main(String[] args) {
Num num = new Num();
num.add();
}
}
运行以上代码后的结果:
到此 多线程基础-02 结束