线程同步
1-数据安全问题
-
是否存在多线程环境
-
是否存在共享数据
-
是否有多条语句操作共享数据
以上条件有任何一个不成立,就不需要考虑线程安全问题,否则需要考虑线程安全问题
处理方法:synchronized(任意对象锁){}
使用同步语句块来解决,同步语句块的作用是,同步语句块中的代码未执行完,下一个线程不能使用CPU执行
2-线程同步的利弊
- 好处:解决多线程操作数据的安全问题
- 坏处:当线程很多的时候,由于每个线程都会去判断同步锁,会严重耗费资源,间接降低了程序效率。
3-同步方法
- 同步方法就是把synchronized关键字添加到方法上
- 格式:
修饰符列表 synchronized 返回值 方法名(形参列表){}
- 同步方法的锁对象是:this
- 格式:
package advanced.nine;
/**
* @author Object
* @description 卖票
* @date 2020/9/13
*/
public class SellTicket implements Runnable{
//可以卖的票数
private int tickets;
public SellTicket() {
}
public SellTicket(int tickets) {
this.tickets = tickets;
}
public int getTickets() {
return tickets;
}
public void setTickets(int tickets) {
this.tickets = tickets;
}
@Override
public void run() {
while (tickets>=0) {
sell();
}
}
//使用同步方法保证数据安全
public synchronized void sell(){
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "卖了一张票,还剩" + tickets + "张");
}
tickets--;
}
}
//=================================
package advanced.nine;
/**
* @author Object
* @description 德云社卖票测试
* @date 2020/9/13
*/
public class Demo02 {
public static void main(String[] args) {
SellTicket st = new SellTicket(10000);
Thread td = new Thread(st,"文化宫");
Thread td1 = new Thread(st,"潘家园");
Thread td2 = new Thread(st,"天安门");
td.start();
td1.start();
td2.start();
}
}
- 同步静态方法:把synchronized方在静态方法的声明处。
- 格式:
修饰符列表 sychronized 返回值 方法名(形参列表){}
- 同步静态方法的锁对象是:类名.class
- 格式:
package advanced.nine;
/**
* @author Object
* @description 卖票
* @date 2020/9/13
*/
public class SellTicket implements Runnable{
private static int tickets;
public SellTicket() {
}
public SellTicket(int tickets) {
this.tickets = tickets;
}
@Override
public void run() {
while (tickets>=0) {
sell();
}
}
//使用同步方法保证数据安全
public static void sell(){
//静态方法中,获取锁对象是 类名.class
synchronized (SellTicket.class) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + "卖了一张票,还剩" + tickets + "张");
}
tickets--;
}
}
}
4-线程安全的类
- StringBuffer
- 线程安全,可变字符串序列
- 需要进行同步的时候使用StringBuffer,不需要同步使用StringBuilder
- Vector
- List 同步集合,如果不需要同步,就使用 ArrayList
- HashTable
- Map 同步集合,如果不需要同步,就使用 HashMap
5-Lock
Lock可以给一段代码加锁,正在执行的对象没有执行完锁包括的内容时,其它线程进不去锁
-
注意锁的使用,加锁和开锁必须要成对出现
package advanced.nine; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; /** * @author Object * @description 卖票 * @date 2020/9/13 */ public class SellTicket implements Runnable{ private int tickets; private Lock lock = new Lock() { @Override public void lock() { } @Override public void lockInterruptibly() throws InterruptedException { } @Override public boolean tryLock() { return false; } @Override public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return false; } @Override public void unlock() { } @Override public Condition newCondition() { return null; } }; public SellTicket() { } public SellTicket(int tickets) { this.tickets = tickets; } @Override public void run() { while (tickets >= 0) { lock.lock(); if (tickets > 0) { System.out.println(Thread.currentThread().getName() + "卖了一张票,还剩" + tickets + "张"); } tickets--; lock.unlock(); } } }