线程同步
1、线程同步就是多个线程并发地访问同一个数据。
2、多线程就是同时去做同样的事情,目的是提高程序的运行效率。
通过“售票”模拟线程同步
/*
* 通过"卖票"模拟线程同步
*/
public class TestTicket {
public static void main(String[] args) {
//创建实现类
SaleTicket st=new SaleTicket();
//创建线程对象去调用实现类
Thread t1=new Thread(st);
Thread t2=new Thread(st);
Thread t3=new Thread(st);
//设置线程名称
t1.setName("售票员1");
t2.setName("售票员2");
t3.setName("售票员3");
//调用start()方法激活线程
t1.start();
t2.start();
t3.start();
}
}
//定义SaleTicket去实现Runnable接口
class SaleTicket implements Runnable{
//定义ticket常量
int ticket=50;
//重写run()方法
public void run() {
while(true)
{
if(ticket>0)
{
try {
Thread.currentThread();
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":\t"+ticket--);
}
else{
break;
}
}
}
}
但是线程共同访问同一数据(线程并发)出现资源访问错误也叫线程安全问题,即打印不合理的数据0票、-1票、同一个票号被打印两次。因为售票员3和售票员2在ticket>0为true时进入if循环,当时处于休眠状态。在售票员3和售票员2休眠的时候由于售票员1打印ticket,此时的ticket=0。但是售票员3和售票员2休眠已经在if循环体里面了,循环的条件ticket>0对他们两个来说不起作用。所以售票员3和售票员2也顺利打印ticket,但是打印的是不合法的数据,因此导致0票和-1票的出现。
同步锁*重点内容*
使用同步锁可以解决线程共同访问同一数据(线程并发)出现资源访问错误的问题/线程安全性问题。
同步锁相当于厕所的门,锁定已经占有的资源,直到用完后才释放资源,别人才可以使用此资源。
同步锁分为同步代码块和同步方法两种。
(一)同步代码块
/*
* 通过"卖票"模拟线程同步
*/
public class TestTicket {
public static void main(String[] args) {
//创建实现类
SaleTicket st=new SaleTicket();
//创建线程对象去调用实现类
Thread t1=new Thread(st);
Thread t2=new Thread(st);
Thread t3=new Thread(st);
//设置线程名称
t1.setName("售票员1");
t2.setName("售票员2");
t3.setName("售票员3");
//调用start()方法激活线程
t1.start();
t2.start();
t3.start();
}
}
//定义SaleTicket去实现Runnable接口
class SaleTicket implements Runnable{
//定义ticket常量
int ticket=50;
//定义一个lock常量
String lock="Lock";
//重写run()方法
public void run() {
while(true)
{
//同步代码块
synchronized(lock){
if(ticket>0)
{
try {
Thread.currentThread();
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":\t"+ticket--);
}
else{
break;
}
}
}
}
}
(二)同步方法
/*
* 通过"卖票"模拟线程同步并采用同方法 解决线程安全性问题
*/
public class TestTicket {
public static void main(String[] args) {
//创建实现类
SaleTicket st=new SaleTicket();
//创建线程对象去调用实现类
Thread t1=new Thread(st);
Thread t2=new Thread(st);
Thread t3=new Thread(st);
//设置线程名称
t1.setName("售票员1");
t2.setName("售票员2");
t3.setName("售票员3");
//调用start()方法激活线程
t1.start();
t2.start();
t3.start();
}
}
//定义SaleTicket去实现Runnable接口
class SaleTicket implements Runnable{
//定义ticket常量
int ticket=50;
//重写run()方法
public void run() {
//一直执行调用sale()方法,直到sale()为false时跳出循环
while(true)
{
if(!sale())
{
break;
}
}
}
//同步方法
public synchronized boolean sale()
{
if(ticket>0)
{
try {
Thread.currentThread();
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":\t"+ticket--);
}
else{
return false;
}
return true;
}
}