线程安全问题是不能产生的,我们可以让一个线程在访问共享数据的时候,无论是否失去了cpu的执行权,让其他的线程只能等待,等待当前线程执行完,其他线程在执行
保证始终是一个线程在执行
解决线程安全问题手段:线程同步
实现同步操作步骤
1.同步代码块
格式:
synchronized(锁对象){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
注意事项:
1.通过代码块中的锁对象,可以使用任意的对象
2.但是必须保证多个线程使用的锁对象是同一个
3.锁对象作用:
把同步代码块锁住,只让一个线程在同步代码块中执行
创建Runnable的实现类RunnableImple
//实现卖票案例:出现了线程安全问题,卖出了重复和不存在的票
public class RunnableImple implements Runnable {
private int ticket = 100;
//创建一个锁对象
Object obj = new Object();
@Override
public void run() {
while (true){
//同步代码块
synchronized (obj){
if (ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket);
ticket--;
}
}
}
}
}
主程序
public class t1 {
public static void main(String[] args){
RunnableImple rnb = new RunnableImple();
new Thread(rnb).start();
new Thread(rnb).start();
new Thread(rnb).start();
}
}
同步技术原理:
同步中的线程,没有执行完毕不会释放锁,同步外的线程没有锁进不去同步
弊端
同步保证了只能有一个线程在同步中执行共享数据保证了数据
程序频繁的判断锁,释放锁,程序的效率会降低
2.同步方法
使用步骤:
1.把访问就共享数据的代码抽取处理,放到一个方法中
2.在方法上添加synchronized修饰符
创建Runntable实现类RunnableImple
//实现卖票案例:出现了线程安全问题,卖出了重复和不存在的票
public class RunnableImple implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true){
payTicket();
}
}
public synchronized void payTicket(){
if (ticket>0){
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket);
ticket--;
}
}
}
主程序
public class t1 {
public static void main(String[] args){
RunnableImple rnb = new RunnableImple();
new Thread(rnb).start();
new Thread(rnb).start();
new Thread(rnb).start();
}
}
静态同步方法
Runnable实现类RunnableImple
//实现卖票案例:出现了线程安全问题,卖出了重复和不存在的票
public class RunnableImple implements Runnable {
private static int ticket = 100;
@Override
public void run() {
while (true){
payTicket();
}
}
public static synchronized void payTicket(){
if (ticket>0){
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket);
ticket--;
}
}
}
主程序
public class t1 {
public static void main(String[] args){
RunnableImple rnb = new RunnableImple();
new Thread(rnb).start();
new Thread(rnb).start();
new Thread(rnb).start();
}
}
静态同步方法锁对象不能是this,this是创建对象之后产生的,静态方法要优先于对象
静态方法的锁对象是RunnableImple.class属性
3.Lock接口的锁机制
使用步骤:
创建Runnable实现类RunnableImple
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//实现卖票案例:出现了线程安全问题,卖出了重复和不存在的票
public class RunnableImple implements Runnable {
private static int ticket = 100;
//1.创建ReentrantLock对象
Lock l = new ReentrantLock();
@Override
public void run() {
while (true){
l.lock();
try {
Thread.sleep(10);
if (ticket>0){
System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket);
ticket--;
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
l.unlock();
}
}
}
}
主程序
扫描二维码关注公众号,回复:
10554706 查看本文章
public class t1 {
public static void main(String[] args){
RunnableImple rnb = new RunnableImple();
new Thread(rnb).start();
new Thread(rnb).start();
new Thread(rnb).start();
}
}
线程状态
生产者消费者模型:等待唤醒
等待唤醒案例
notify()唤醒一个等待时间最久的线程
notifyall()唤醒所有等待线程
public class t1 {
public static void main(String[] args){
//创建锁对象
Object obj = new Object();
//顾客
new Thread(){
@Override
public void run() {
while (true){//一直等待买包子
//保证等待和唤醒只能有一个执行
synchronized (obj){
System.out.println("点餐");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
//唤醒之后执行的代码
System.out.println("端上桌开吃");
System.out.println("-----------");
}
}
}
}.start();
new Thread(){
@Override
public void run() {
while (true){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (obj){
System.out.println("告知顾客取餐");
obj.notify();
}
}
}
}.start();
}
}
创建一个资源类:包子类
public class rube {
//皮
String skin;
String stuffing;
boolean state = false;
}
创建生产者类:包子铺类
public class productionImpl extends Thread {
private rube bz;
public productionImpl(rube bz) {
this.bz = bz;
}
@Override
public void run() {
int count = 0;
while (true){
synchronized (bz){
if (bz.state==true){
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (count%2==0){
bz.skin="薄皮";
bz.stuffing="三鲜";
}else{
bz.skin="冰皮";
bz.stuffing="牛肉";
}
count++;
System.out.println("包子正在制作:"+bz.skin+bz.stuffing+"包子");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
bz.state=true;
bz.notify();
System.out.println("包子已经出锅上桌了 ");
}
}
}
}
创建消费者类:顾客类
public class consumerImple extends Thread {
private rube bz;
public consumerImple(rube bz) {
this.bz = bz;
}
@Override
public void run() {
while (true){
synchronized (bz){
if (bz.state==false){
try {
bz.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("正在吃"+bz.skin+bz.stuffing+"的包子");
bz.state=false;
bz.notify();
System.out.println("吃完了所有的包子,赶紧上菜!");
}
}
}
}
主程序
public class t1 {
public static void main(String[] args){
rube bz = new rube();
new productionImpl(bz).start();
new consumerImple(bz).start();
}
}