单任务多线程 安全
线程状态
线程安全
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的
买票例子
原理图:
代码:
package com.oracle.Demo03; public class Tickets implements Runnable{ //把线程的共享数据做成成员变量 private int tickets=100; //锁对象 private Object mutex=new Object(); public void run() { while(true){ //同步代码快解决线程安全问题 synchronized (mutex) { if (tickets>0) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"售出第"+ tickets--+"张票"); } } } } } package com.oracle.Demo03; public class Demo01 { public static void main(String[] args) { //创建创建线程任务 Tickets03 t=new Tickets03(); //创建3个线程对象 Thread t1=new Thread(t); Thread t2=new Thread(t); Thread t3=new Thread(t); //开启线程 t1.start(); t2.start(); t3.start(); }
不安全原理图
线程同步(线程安全处理Synchronized)
线程同步的方式有两种:
方式1:同步代码块
方式2:同步方法
同步代码块: 在代码块声明上 加上synchronized
同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。
public class Ticket implements Runnable { //共100票 int ticket = 100; //定义锁对象 Object lock = new Object(); @Override public void run() { //模拟卖票 while(true){ //同步代码块 synchronized (lock){ if (ticket > 0) { //模拟电影选坐的操作 try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket--); } } } }
同步方法
同步方法:在方法声明上加上synchronized
同步方法中的锁对象是 this
package com.oracle.Demo03; public class Tickets02 implements Runnable { // 把线程的共享数据做成成员变量 private int tickets = 100; public void run() { while (true) { sale(); } } //同步方法 //StringBuffer 慢 所有方法都是同步方法 安全 //StringBuilder 快 所有方法都是非同步方法 不安全 public synchronized void sale(){ if (tickets > 0) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "售出第" + tickets-- + "张票"); } } } package com.oracle.Demo03; public class Demo01 { public static void main(String[] args) { //创建创建线程任务 Tickets03 t=new Tickets03(); //创建3个线程对象 Thread t1=new Thread(t); Thread t2=new Thread(t); Thread t3=new Thread(t); //开启线程 t1.start(); t2.start(); t3.start(); } }
注意:StringBuffer 慢 所有方法都是同步方法 安全
StringBuilder 快 所有方法都是非同步方法 不安全
Lock接口
Lock提供了一个更加面对对象的锁,在该锁中提供了更多的操作锁的功能
package com.oracle.Demo03; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Tickets03 implements Runnable{ //把线程的共享数据做成成员变量 private int tickets=100; private Lock lock=new ReentrantLock(); private Object mutex=new Object(); public void run() { while(true){ lock.lock(); if (tickets>0) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"售出第"+ tickets--+"张票"); lock.unlock(); } } } }