线程同步代码块
当多个线程共享一个数据的时候,为了使相同的数据能不被线程多次运用,而出现的数据重复的问题,可以通过给同步代码块上锁的操作来实现
-
格式:
synchronized(任意对象){
多个线程共同操作的代码
}
-
同步的好处和弊端:
-
好处:可以解决多线程的数据安全问题;
-
弊端:因为会上锁,这样会很消耗资源,因此会降低程序的运行效率;
-
案例:卖票
1、定义一个类SellTicket实现Runnable接口:
package 线程;
public class SellTickets implements Runnable {
private int a=100;
Object obj=new Object();
@Override
public void run() {
synchronized (obj) {
//窗口卖票的方法
while (true) {
if (a > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "出售了第:" + a + "张票");
a--;
}
}
}
}
}
2、定义一个测试类SellTicketDemo,里面有main方法,代码步骤如下
package 线程;
public class SellTickets_Demo {
public static void main(String[] args) {
//创建SellTicket类的对象
SellTickets st=new SellTickets();
//创建三个Thread类的对象,把SellTicket对象作为构造方法的参数,并给出对应的窗口名称
Thread t1=new Thread(st,"窗口1");
Thread t2=new Thread(st,"窗口2");
Thread t3=new Thread(st,"窗口3");
//启动线程
t1.start();
t2.start();
t3.start();
}
}
同步方法
同步方法:
-
就是把synchronized关键字加到方法上
格式:
-
修饰符synchronized返回值类型方法名(方法参数){}
同步方法的锁对象是什么呢?
-
this
同步静态方法:
-
就是把synchronized关键字加到静态方法上
格式:
-
修饰符static synchronized返回值类型方法名(方法参数){}
同步静态方法的锁对象是什么呢?
-
类名.class
例题:
创建一个SellTickets类
package 线程;
public class SellTickets implements Runnable {
private int a=1000;
private Object obj=new Object();
int x=0;
@Override
public void run() {
if(x%2==0){
while (true){
synchronized (this) {
if (a > 0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "出售了第:" + a + "张票");
a--;
}
}
}
}else{
show();
}
x++;
}
public synchronized void show(){
while (true){
if (a > 0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "出售了第:" + a + "张票");
a--;
}
}
}
}
写一个实现类:
package 线程;
public class SellTickets_Demo {
public static void main(String[] args) {
//创建SellTicket类的对象
SellTickets st=new SellTickets();
//创建三个Thread类的对象,把SellTicket对象作为构造方法的参数,并给出对应的窗口名称
Thread t1=new Thread(st,"窗口1");
t1.setPriority(5);
Thread t2=new Thread(st,"窗口2");
t2.setPriority(8);
Thread t3=new Thread(st,"窗口3");
t2.setPriority(8);
//启动线程
t1.start();
t2.start();
t3.start();
}
}
2.10、Lock锁
Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化
Lock中提供了获得锁和释放锁的方法:
-
void lock():获得锁
-
void unlock():释放锁
测试:
创建一个MyLock实现类
package 线程.Lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyLock implements Runnable{
private int a=1000;
//Lock是一个接口不能直接实例化,需要一个ReentrantLock()实现类来实例化
private Lock lock=new ReentrantLock();
@Override
public void run() {
lock.lock();//获得锁
//用try{}方法是为了在方法出错的时候依旧可以关闭锁
try {
while (true) {
if (a > 0) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "出售了第:" + a + "张票");
a--;
}
}
}finally {
lock.unlock();//关闭锁
}
}
}
测试类:
package 线程.Lock;
public class MyLock_Demo {
public static void main(String[] args) {
//创建SellTicket类的对象
MyLock ml=new MyLock();
//创建三个Thread类的对象,把SellTicket对象作为构造方法的参数,并给出对应的窗口名称
Thread t1=new Thread(ml,"窗口1");
t1.setPriority(5);
Thread t2=new Thread(ml,"窗口2");
t2.setPriority(8);
Thread t3=new Thread(ml,"窗口3");
t2.setPriority(8);
//启动线程
t1.start();
t2.start();
t3.start();
}
}