同步技术的原理
使用一个锁对象,这个锁对象叫同步锁,也叫对象锁,也可以叫对象监视器。在同步中的线程,没有执行完毕不会释放锁,同步外的线程没有锁进不去同步。同步保证了只能有一个先线程在同步中执行共享数据,进而保证了安全,但程序频繁的判断锁,获取锁,释放锁,程序的效率会降低。例子如下:
// 同步技术的格式
synchronize(同步锁) {
需要同步操作的对象
}
public class Demo{
public static void main(String[] args) {
// 创建接口实现类对象
RunnableImpl ru = new RunnableImpl();
// 创建四个线程
Thread th1 = new Thread(ru);
Thread th2 = new Thread(ru);
Thread th3 = new Thread(ru);
Thread th4 = new Thread(ru);
// 启动线程
th1.start();
th2.start();
th3.start();
th4.start();
}
}
public class RunnableImpl implements Runnable{
// 定义一个多线程的票源
private int ticket = 50;
// 设置了一个Object的锁对象
Object obj = new Object();
// 设置线程任务:卖票
@Override
public void run() {
while(true){
// 同步代码块
synchronized (obj) {
if (ticket > 0) {
try {
// 解决线程安全问题出现的概率,让程序睡眠
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"还剩"+ticket+"张票");
ticket--;
}
}
}
}
}
同步方法
同步方法:使用synchronize修饰的方法,保证线程1执行时,其他的线程只能在方法外等待。同步方法默认的锁对象就是线程的实现类对象(this)。
public synchronize void method () {
可能会产生线程安全问题的代码块
}
使用步骤:
- 1.把访问的共享数据的代码抽取出来,放到一个方法中
- 2.在方法上添加synchronize的修饰符
public class Demo{
public static void main(String[] args) {
// 创建接口实现类对象
RunnableImpl ru = new RunnableImpl();
// 创建四个线程
Thread th1 = new Thread(ru);
Thread th2 = new Thread(ru);
Thread th3 = new Thread(ru);
Thread th4 = new Thread(ru);
// 启动线程
th1.start();
th2.start();
th3.start();
th4.start();
}
}
// 输出结果
Thread-0还剩50张票
Thread-0还剩49张票
Thread-0还剩48张票
Thread-0还剩47张票
Thread-0还剩46张票
Thread-2还剩45张票
Thread-2还剩44张票
Thread-2还剩43张票
Thread-2还剩42张票
Thread-2还剩41张票
Thread-2还剩40张票
Thread-2还剩39张票
Thread-2还剩38张票
Thread-2还剩37张票
Thread-2还剩36张票
Thread-2还剩35张票
Thread-2还剩34张票
Thread-2还剩33张票
Thread-2还剩32张票
Thread-2还剩31张票
Thread-2还剩30张票
Thread-2还剩29张票
Thread-2还剩28张票
Thread-2还剩27张票
Thread-2还剩26张票
Thread-2还剩25张票
Thread-2还剩24张票
Thread-2还剩23张票
Thread-2还剩22张票
Thread-2还剩21张票
Thread-2还剩20张票
Thread-2还剩19张票
Thread-2还剩18张票
Thread-2还剩17张票
Thread-2还剩16张票
Thread-2还剩15张票
Thread-2还剩14张票
Thread-2还剩13张票
Thread-2还剩12张票
Thread-2还剩11张票
Thread-2还剩10张票
Thread-2还剩9张票
Thread-2还剩8张票
Thread-2还剩7张票
Thread-2还剩6张票
Thread-2还剩5张票
Thread-2还剩4张票
Thread-2还剩3张票
Thread-2还剩2张票
Thread-2还剩1张票
public class RunnableImpl implements Runnable{
private int ticket = 50;
Object obj = new Object();
@Override
public void run() {
while(true){
method();
}
}
// 带有synchronize修饰符的方法
public synchronized void method () {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"还剩"+ticket+"张票");
ticket--;
}
}
}
静态同步方法
静态同步方法的锁对象是线程实现类的class属性(Runnable.class)
格式如下:
public static synchronize void method () {
可能会产生线程安全问题的代码块
}
public class RunnableImpl implements Runnable{
private static int ticket = 50;
Object obj = new Object();
@Override
public void run() {
while(true){
method();
}
}
public static synchronized void method () {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"还剩"+ticket+"张票");
ticket--;
}
}
}
public class Demo{
public static void main(String[] args) {
// 创建接口实现类对象
RunnableImpl ru = new RunnableImpl();
// 创建四个线程
Thread th1 = new Thread(ru);
Thread th2 = new Thread(ru);
Thread th3 = new Thread(ru);
Thread th4 = new Thread(ru);
// 启动线程
th1.start();
th2.start();
th3.start();
th4.start();
}
}
Lock锁
java.util.concurrent.locks.Lock机制提供了比synchronize和synchronize方法更广泛的锁定操作,同步代码块和同步方法有的功能Lock锁都有,除此之外更强大,体现在面对对象。
Lock锁又称同步锁,加锁和释放锁方法化,Lock接口的方法,如下:
- public void lock():获取锁
- public void unlock():释放锁
使用步骤: - 1.在成员位置创建ReentrantLock对象
- 2.在可能出现安全问题的代码前调用Lock()方法,获取锁。
- 3.在可能出现安全问题的代码后调用unlock()方法,释放锁
例子如下:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class RunnableImpl implements Runnable{
private int ticket = 50;
Object obj = new Object();
Lock l = new ReentrantLock();
@Override
public void run() {
while(true){
l.lock();
if (ticket > 0) {
try {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+"还剩"+ticket+"张票");
ticket--;
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
l.unlock();
}
}
}
}
}