目录
线程间的等待唤醒机制
void wait () 在其他线程调用此对象的 notify () 方法或 notifyAll () 方法前,导致当前线程等待
void notify () 唤醒在此对象监视器上等待的单个线程,随机唤醒。
//资源 包子
public class Buns {
public String name;
public int price;
//定义一个标记
public boolean flag = false; //false 表示没有资源,true表示有资源。
}
//生产者线程
public class SetThread extends Thread {
private Buns buns;
int i = 0;
public SetThread(Buns buns) {
this.buns = buns;
}
@Override
public void run() {
while (true) {
synchronized (buns) {
//生产线程,生产出了资源,也就是有资源,就等着,不能干等着,得通知消费线程,消费资源
if (buns.flag) {
//进来了,表示有资源
try {
buns.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//生产了资源
if (i % 2 == 0) {
buns.name = "肉包子";
buns.price = 3;
} else {
buns.name = "素包子";
buns.price = 2;
}
//通知消费者线程
buns.flag = true; //修改标记
buns.notify(); //唤醒等待的线程,我还是可以再次争抢
}
i++;
}
}
}
//消费者线程
public class GetThread extends Thread {
private Buns buns;
public GetThread(Buns buns) {
this.buns = buns;
}
@Override
public void run() {
while (true) {
synchronized (buns) {
if (!buns.flag) {
//进来了,说明没有资源
try {
buns.wait(); //线程一旦等待,就会释放锁,下次被唤醒,就从这里醒来,也就是从哪里等待,从哪里醒来
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//消费资源
System.out.println(buns.name + "====" + buns.price);
//通知生产线程去生产
buns.flag = false;
buns.notify();
}
}
}
}
public class MyTest {
public static void main(String[] args) {
//生成者线程 SetThread
//消费者线程 GetThread
//资源 Bun 两个线程共享
//出现线程安全问题,符合的条件
//1.是多线程环境
//2.多个线程有共享资源
//3.有多条语句在操作这个共享资源
//生产线程,生产出了资源,也就是有资源,就等着,不能干等着,得通知消费线程,消费资源
//消费线程,有了资源,消费资源,消费后资源没有了,就等着,不能干等着,得通知生产线程,去生产。
/* void notify ()
唤醒在此对象监视器上等待的单个线程。
void notifyAll ()
唤醒在此对象监视器上等待的所有线程。
void wait ()
在其他线程调用此对象的 notify () 方法或 notifyAll () 方法前,导致当前线程等待。
void wait ( long timeout)
在其他线程调用此对象的 notify () 方法或 notifyAll () 方法,或者超过指定的时间量前,导致当前线程等待。*/
Buns buns = new Buns();
SetThread th1 = new SetThread(buns);
GetThread th2 = new GetThread(buns);
th2.start();
th1.start();
}
}
wait()和sleep()的区别
Wait和Sleep的区别:
1.它们最大本质的区别是,Sleep()不释放同步锁,Wait()释放同步锁。
2.还有用法的上的不同是:Sleep(milliseconds)可以用时间指定来使他自动醒过来,如果时间不
3.到你只能调用Interreput()来强行打断;Wait()可以用Notify()直接唤起。
4.这两个方法来自不同的类分别是Thread和Object
5.最主要是Sleep方法没有释放锁,而Wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
内存可见性问题 volatile
当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取
时,它会去内存中读取新值。
而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定
的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。
另外,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个
线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保
证可见性。
public class MyTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
while (true) {
if (myRunnable.getFlag()) { //
System.out.println("进来了~~~");
break;
}
}
}
}
class MyRunnable implements Runnable {
//volatile 可以保证线程的内存可见性的问题,但是不能保证原子性的问题。
//当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。
volatile boolean flag = false;
public boolean getFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//修改flag的值
flag = true;
System.out.println("线程修改了flag的值是:" + flag);
}
}
原子性问题,不能使用volatile,可以使用synchronized,但效率低,性能下降
用CAS算法(Compare-And-Swap)
CAS 是一种无锁的非阻塞算法的实现
CAS 包含了 3 个操作数:
需要读写的内存值 V
进行比较的值 A
拟写入的新值 B
AtomicInteger 原子变量,实现了 CAS 算法
AtomicInteger i = new AtomicInteger();
public class MyTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(myRunnable);
thread.start();
}
}
}
class MyRunnable implements Runnable {
//int i = 1;
// AtomicInteger(int initialValue) 创建具有给定初始值的新 AtomicInteger.
//原子变量,实现CAS算法
AtomicInteger i = new AtomicInteger(1);
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + i.getAndIncrement()); //
}
}
}
线程的状态
匿名内部类创建线程
普通方法:
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程执行了");
}
}
public class MyTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程执行了2222");
}
}
public class MyTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
new Thread(myThread).start();
}
}
利用匿名内部类创建
public class MyTest {
public static void main(String[] args) {
//采用匿名内部类的方式来创建线程
//方式1
new Thread() {
@Override
public void run() {
System.out.println("执行了111111");
}
}.start();
//方式2:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("任务执行了");
}
}).start();
}
}