方式一:同步代码块
* 关键字
* synchronized(同步监视器)
* {
* //需要被同步的代码
* }
* 1.说明:操作共享数据的代码即为需被同步的代码
* 2.共享数据:多个线程共同操作的变量
* 3.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。//Object obj=new Object();
* 要求:多个线程必须要共用同一把锁
方式二:同步方法
* 如果操作共享数据的代码完整声明在一个方法中,我们不妨将此方法声明为同步的。
* synchronized关键字
* public synchronized void show()
* 同步方法依然涉及同步监视器,只是不需要显示声明
* 非静态的同步方法,同步监视器是this
* 静态的同步方法,同步监视器是当前类本身
方式三:Lock锁
* 1.实例化ReentrantLock
* private ReentrantLock lock=new ReentrantLock();
* 2.调用锁定方法
* lock.lock()
* 3.调用解锁方法
* lock.unlock()
/**
* 例子:创建三个窗口卖票,总票数100张,使用实现Runable接口的方式
*存在线程安全问题,待解决
*
* 1.问题:卖票过程中,出现了重票、错票->线程安全问题
* 2.原因:当某个线程操作车票的过程中,尚未完成操作时,其他线程也参与进来操作车票
* 共享数据(共享信号量):车票数ticket
* 3.解决:锁;
* 4.在java中,通过同步机制来解决线程的安全问题
*
* 方式一:同步代码块
* 关键字
* synchronized(同步监视器)
* {
* //需要被同步的代码
* }
* 1.说明:操作共享数据的代码即为需被同步的代码
* 2.共享数据:多个线程共同操作的变量
* 3.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。//Object obj=new Object();
* 要求:多个线程必须要共用同一把锁
*
*
*
* 方法二:同步方法
* 如果操作共享数据的代码完整声明在一个方法中,我们不妨将此方法声明为同步的。
* synchronized关键字
* public synchronized void show()
* 同步方法依然涉及同步监视器,只是不需要显示声明
* 非静态的同步方法,同步监视器是this
* 静态的同步方法,同步监视器是当前类本身
*
*
* 5.同步的方式,解决了线程的安全问题。---好处
* 操作同步代码时只能有一个线程参与,其他线程等待,相当于是一个单线程的过程,效率低----局限性
* 死锁问题
* 6.同步监视器是否唯一
*
* @author orz
*/
class Window1 implements Runnable
{
private int ticket=100;
//同步监视器
Object obj=new Object();
@Override
public void run() {
while (true)
{
//同步代码块方法实现数据共享
synchronized (obj)
{
if(ticket>0)
{
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+ticket);
ticket--;
}
else
{
break;
}
}
}
}
}
public class WindowTest {
public static void main(String[] args) {
Window1 w=new Window1();
Thread t1=new Thread(w);
Thread t2=new Thread(w);
Thread t3=new Thread(w);
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
/**
* 线程同步
*
*多线程共享变量
*
* 例子:创建三个窗口卖票,总票数100张,使用继承Thread类的方式
*存在线程安全问题,待解决
* 使用同步代码块方法解决线程安全问题
*
*
* @author orz
*/
class Window2 extends Thread
{
//类变量,共用同一个变量
private static int ticket=100;
//锁
private static Object obj=new Object();
@Override
public void run() {
while (true)
{
synchronized (obj)
{
if(ticket>0)
{
System.out.println(getName()+":卖票,票号为:"+ticket);
ticket--;
}
else
{
break;
}
}
}
}
}
public class WindowTest2 {
public static void main(String[] args) {
Window2 w1=new Window2();
Window2 w2=new Window2();
Window2 w3=new Window2();
w1.setName("窗口一");
w2.setName("窗口二");
w3.setName("窗口三");
w1.start();
w2.start();
w3.start();
}
}
/**
* 使用同步方法来解决实现Runable接口的线程安全问题
*
* @author orz
*/
class Window3 implements Runnable
{
private int ticket=100;
public synchronized void show()
{
if(ticket>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+ticket);
ticket--;
}
}
@Override
public void run() {
while (true)
{
show();
}
}
}
public class WindowTest3 {
public static void main(String[] args) {
Window3 w=new Window3();
Thread t1=new Thread(w);
Thread t2=new Thread(w);
Thread t3=new Thread(w);
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
/**
* 使用同步方法来解决继承Thread类的线程安全问题
* @author orz
*/
class Window4 extends Thread
{
//类变量,共用同一个变量
private static int ticket=100;
//同步监视器:WindowTest4.class
//必须声明为静态方法
public static synchronized void show()
{
if(ticket>0)
{
System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+ticket);
ticket--;
}
}
@Override
public void run() {
while (true)
{
show();
}
}
}
public class WindowTest4 {
public static void main(String[] args) {
Window4 w1=new Window4();
Window4 w2=new Window4();
Window4 w3=new Window4();
w1.setName("窗口一");
w2.setName("窗口二");
w3.setName("窗口三");
w1.start();
w2.start();
w3.start();
}
}
import java.util.concurrent.locks.ReentrantLock;
/**
* 解决线程安全问题的方式三:Lock锁
*
* 1.实例化ReentrantLock
* private ReentrantLock lock=new ReentrantLock();
* 2.调用锁定方法
* lock.lock()
* 3.调用解锁方法
* lock.unlock();
*
*
*
* 面试题:synchronized与lock异同
* 相同:
* 不同:
* synchronized机制执行完相应的同步代码之后,自动释放同步监视器
* Lock需要手动的启动同步(lock()),结束同步也需要手动实现(unlock())
*
*
* Lock、同步代码块、同步方法
* @author orz
*/
class Window5 implements Runnable{
private int ticket=100;
/**
* 1.实例化ReentrantLock
*/
private ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
while (true)
{
//2.调用锁定方法
try{lock.lock();
if (ticket>0)
{
try
{
Thread.sleep(100);
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":售票,票号为:"+ticket);
ticket--;
}
else
{
break;
}
}
//3.调用解锁方法
finally {
lock.unlock();
}
}
}
}
public class LockTest {
public static void main(String[] args) {
Window5 w=new Window5();
Thread t1=new Thread(w);
Thread t2=new Thread(w);
Thread t3=new Thread(w);
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}