线程安全问题
原因
多个线程同时操作同一个数据就会出现线程安全问题
解决思想
多个线程同时只能有一个线程对数据进行操作
解决方案
方案1: 同步代码块
语法:
synchronized(锁对象){
要同步的代码
}
上锁与开锁:
当某一个线程进入synchronized代码块中,其锁对象就会上锁,此时别的线程就无法进入,只能在外面等待开锁
当一个线程执行完synchronized代码块中的代码,此时锁对象就会开锁
注意:
所有的对象都可以作为锁对象
要保证多个线程的锁对象是同一个对象
方案2: 同步方法
语法:
访问权限修饰符 synchronized 返回值类型 方法名(形参列表){
方法体(要同步的代码)
}
注意:
同步方法的锁对象是调用该方法的对象(同步方法的锁对象就是this)
方案3: 同步静态方法
语法:
访问权限修饰符 synchronized static 返回值类型 方法名(形参列表){
方法体(要同步的代码)
}
注意:
同步静态方法的锁对象是该方法所属类的类对象
类对象: 一个类被JVM加载时会产生一个类对象,该对象包含该类的所有信息,如该类的包名,类名,父类名,实现的接口名,属性数量,属性名,方法数量,方法名等信息
因为一个类只会被加载一次,所以一个类只有一个类对象
死锁(了解)
目的
了解死锁产生的原因
原因
多个线程相互持有对方所需的锁资源
如何避免
尽量不要在同步中使用同步
线程间通讯
方法:
唤醒
锁对象.notify();
作用: 随机唤醒一个正在休眠的线程
锁对象.notifyAll();
作用: 唤醒所有正在休眠的线程
注意: 只能唤醒使用该锁对象使其休眠的线程
休眠
锁对象.wait();
作用: 让当前线程进入无限期休眠
锁对象.wait(timeout);
作用: 让当前线程有限期休眠,参数为休眠时间,单位毫秒
锁对象.wait(timeout, nanos);
作用: 让当前线程有限期休眠,休眠时间毫秒 + 纳秒
参数1休眠时间,单位毫秒
参数2休眠时间,单位纳秒
wait()与sleep()的区别:
wait():
由Object类提供的普通方法
只能在同步中使用
休眠期间会释放持有的锁对象
sleep():
由Thread类提供的静态方法
可以在同步中,也可以在同步外使用
休眠期间不会释放持有的锁对象
注意:
1.该方法是由Object类提供的
2.只能在同步代码块或同步方法中使用
3.必须使用该同步代码块或同步方法的锁对象调用
案例:
龟兔百米赛跑
注意:
乌龟每秒跑1米
兔子每秒跑10米
总共跑了100米
兔子跑到80米后睡觉了,乌龟跑完后,被兔子听到,兔子才跑完剩余的20米
分析:
乌龟线程
任务: 跑100米,跑完通知兔子
速度: 1秒1米
兔子线程
任务: 跑100米,跑到80米进入无限期休眠
速度: 1秒10米
生产者与消费者模式
目的: 模拟工厂生产与销售的情况
分析:
销售人员类
属性:
工厂
方法:
销售
无限使用工厂对象调用销售方法
生产人员类
属性:
工厂
方法:
生产
无限使用工厂对象调用生产方法
工厂类
属性:
商品数量
最大商品数量
方法:
生产的方法: 同步方法
判断商品数量 < 最大商品数量
true: 继续生产
商品数量 + 1
打印xxx生产了一个商品,目前库存xxx个商品
唤醒销售者线程
false
停止当前生产,等待销售
打印库存已满,xxx停止生产
销售的方法: 同步方法
判断商品数量 > 0
true: 可以销售
商品数量 - 1
打印xxx销售了一个商品,目前库存xxx个商品
唤醒生产者线程
false: 无货
停止销售,等待生产
打印无货,xxx停止销售
环境类
创建一个工厂
创建几个生产者
创建几个销售者
启动生产者与销售者
练习
1.四个窗口各自销售100张票
2.四个窗口共同销售1000张票
3.写一个死锁
4.完成龟兔赛跑
5.完成生产者与消费者
6.使用两个线程
1个线程打印1~26
1个线程打印a~z
要求:打印输出结果为1a2b3c4d5e6f....26z
7.使用两个线程
1个线程打印1~52
1个线程打印a~z
要求:打印输出结果为12a34b56c78d910e1112f....5152z
package test01;
public class MyRunnable implements Runnable{
private int count = 100;
@Override
public void run() {
while(count > 0) {
count--;
String name = Thread.currentThread().getName();
System.out.println(name + "卖了1张票, 还剩余" + count + "张票");
}
}
}
package test01;
public class Test {
public static void main(String[] args) {
new Thread(new MyRunnable(), "窗口一").start();
new Thread(new MyRunnable(), "窗口二").start();
new Thread(new MyRunnable(), "窗口三").start();
new Thread(new MyRunnable(), "窗口四").start();
}
}
运行结果
package test02;
public class MyRunnable implements Runnable{
private int count = 1000;
private final Object LOCK = new Object();
@Override
public void run() {
while(count > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (LOCK) {
if(count <= 0) {
return;
}
count--;
String name = Thread.currentThread().getName();
System.out.println(name + "卖了1张票, 还剩余" + count + "张票");
}
}
}
}
package test02;
public class Test {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
new Thread(runnable, "窗口一").start();
new Thread(runnable, "窗口二").start();
new Thread(runnable, "窗口三").start();
new Thread(runnable, "窗口四").start();
}
}
运行结果
package test03;
public class Test {
public static void main(String[] args) {
Object lock01 = new Object();
Object lock02 = new Object();
Thread thread01 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程一开始");
synchronized (lock01) {
System.out.println("进入线程一锁一");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock02) {
System.out.println("进入线程一锁二");
}
}
System.out.println("线程一结束");
}
});
Thread thread02 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程二开始");
synchronized (lock02) {
System.out.println("进入线程二锁二");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock01) {
System.out.println("进入线程二锁一");
}
}
System.out.println("线程二结束");
}
});
thread01.start();
thread02.start();
}
}
运行结果
package test04;
public interface LockInterface {
public static final Object LOCK = new Object();
}
package test04;
public class WGRunnable implements Runnable{
@Override
public void run() {
for(int i = 1; i <= 100; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("乌龟跑了" + i + "米");
}
System.out.println("乌龟跑完100米了, 乌龟赢了");
synchronized (LockInterface.LOCK) {
LockInterface.LOCK.notify();
}
}
}
package test04;
public class TZRunnable implements Runnable{
@Override
public void run() {
for(int i = 10; i <= 100; i+=10) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("兔子跑了" + i + "米");
if(i == 80) {
System.out.println("兔子睡着了");
synchronized (LockInterface.LOCK) {
try {
LockInterface.LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
System.out.println("兔子跑完100米了");
}
}
package test04;
public class Test {
public static void main(String[] args) {
new Thread(new WGRunnable()).start();
new Thread(new TZRunnable()).start();
}
}
运行结果
package test05;
public class Factory {
private int num = 0; //商品数量
private final int MAX_NUM = 100; //商品最大数量
public synchronized void product() {
String name = Thread.currentThread().getName();
if(num < MAX_NUM) {
num++;
System.out.println(name + "生产了1件商品, 现有商品" + num +"件");
this.notifyAll();
}
else {
System.out.println("库房已满, " + name + "停止生产");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void sell() {
String name = Thread.currentThread().getName();
if(num > 0) {
num--;
System.out.println(name + "销售了1件商品, 现有商品" + num +"件");
this.notifyAll();
}
else {
System.out.println("库房无货, " + name + "停止销售");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package test05;
import java.util.Random;
public class ProductRunnable implements Runnable{
private Factory factory;
public ProductRunnable(Factory factory) {
this.factory = factory;
}
@Override
public void run() {
Random random = new Random();
while(true) {
int num = random.nextInt(10) + 1;
try {
Thread.sleep(num * 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
factory.product();
}
}
}
package test05;
import java.util.Random;
public class SellRunnable implements Runnable{
private Factory factory;
public SellRunnable(Factory factory) {
this.factory = factory;
}
@Override
public void run() {
Random random = new Random();
while(true) {
int num = random.nextInt(10) + 1;
try {
Thread.sleep(num * 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
factory.sell();
}
}
}
package test05;
public class Test {
public static void main(String[] args) {
Factory factory = new Factory();
ProductRunnable pr = new ProductRunnable(factory);
SellRunnable sr = new SellRunnable(factory);
new Thread(pr, "生产人员一").start();
new Thread(pr, "生产人员二").start();
new Thread(pr, "生产人员三").start();
new Thread(sr, "销售人员一").start();
new Thread(sr, "销售人员二").start();
new Thread(sr, "销售人员三").start();
}
}
运行结果
package test06;
public class Test02 {
public static void main(String[] args) {
Object lock = new Object();
//打印数字
Thread thread01 = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 1; i < 27; i++) {
System.out.print(i);
synchronized (lock) {
lock.notify();
if(i != 26) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
});
//打印字母
Thread thread02 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i = 97; i < 123; i++) {
char c = (char)i;
System.out.print(c);
synchronized (lock) {
lock.notify();
if(i != 122) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
});
thread01.start();
thread02.start();
}
}
运行结果
package test07;
public class Test02 {
public static void main(String[] args) {
Object lock = new Object();
//打印数字
Thread thread01 = new Thread(new Runnable() {
@Override
public void run() {
for(int i = 1; i < 53; i++) {
System.out.print(i);
if(i % 2 == 0) {
synchronized (lock) {
lock.notify();
if(i != 52) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
});
//打印字母
Thread thread02 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i = 97; i < 123; i++) {
char c = (char)i;
System.out.print(c);
synchronized (lock) {
lock.notify();
if(i != 122) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
});
thread01.start();
thread02.start();
}
}
运行结果