一、synchronized加锁方式
(一)、synchronized修饰代码块:
1、格式
synchronized(同步对象){
同步代码块;
}
2、用来记录有没有线程进入同步代码块,在对象头中有一块空间用来记录有没有线程进入到同步代码块
3、同步对象要求:多个线程对应的对象必须是同一个
4、举例:窗口买票
eg1:继承Thread方法
public class TicketThread extends Thread{
static int t=10;
static Object object=new Object();
@Override
public void run() {
while (true){
synchronized (object){
if (t>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买了"+t+"票");
t--;
}else break;
}
}
}
}
public class Test {
public static void main(String[] args) {
TicketThread thread1=new TicketThread();
thread1.setName("窗口1");
TicketThread thread2=new TicketThread();
thread2.setName("窗口2");
thread1.start();
thread2.start();
}
}
eg2:继承Runnable接口
public class TicketTask1 implements Runnable{
int t=10;
@Override
public void run() {
synchronized (this){
while (true){
if (t>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"买了"+t+"票");
t--;
}else break;
}
}
}
}
public class Test {
public static void main(String[] args) {
TicketTask1 ticketTask=new TicketTask1();
Thread thread1=new Thread(ticketTask);
thread1.setName("窗口1");
Thread thread2=new Thread(ticketTask);
thread2.setName("窗口2");
thread1.start();
thread2.start();
}
}
(二)、synchronized修饰方法:
1、此时不需要我们提供锁,同步对象会有默认的
2、若修饰非静态的方法,那么同步对象就是this
若修饰静态方法,同步对象就是当前类的Class对象
注:当前类的Class 对象:一个类加载到内存后会为这个类创建一个唯一的Class类对象
3、举例:窗口买票
eg1:继承Thread方法
public class TicketThread2 extends Thread{
static int t=10;
@Override
public void run() {
while (true){
if (t<=0)break;
ticket();
}
}
private static synchronized void ticket(){
/*try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
if (t>0){
System.out.println(Thread.currentThread().getName()+"买了"+t+"票");
t--;
}
}
}
public class Test {
public static void main(String[] args) {
TicketThread2 thread1=new TicketThread2();
thread1.setName("窗口1");
TicketThread2 thread2=new TicketThread2();
thread2.setName("窗口2");
thread1.start();
thread2.start();
}
}
eg2:继承Runnable接口
public class TicketTask2 implements Runnable{
int t=10;
@Override
public void run() {
while (true){
if (t<=0)break;
ticket();
}
}
private synchronized void ticket(){
/*try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
if (t>0){
System.out.println(Thread.currentThread().getName()+"买了"+t+"票");
t--;
}
}
}
public class Test {
public static void main(String[] args) {
TicketTask2 ticketTask=new TicketTask2();
Thread thread1=new Thread(ticketTask);
thread1.setName("窗口1");
Thread thread2=new Thread(ticketTask);
thread2.setName("窗口2");
thread1.start();
thread2.start();
}
}
二、ReentrantLock加锁方式
jdk中ReentrantLock类实现加锁
ReentrantLock只能对代码块进行加锁,不能对方法加锁
(一)、修饰代码块
import java.util.concurrent.locks.ReentrantLock;
public class TicketThread implements Runnable{
int t=10;
ReentrantLock reentrantLock=new ReentrantLock();
@Override
public void run() {
while (true){
try {
reentrantLock.lock();
if (t > 0) {
/*try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
System.out.println(Thread.currentThread().getName() + "买了" + t + "票");
t--;
}else break;
}finally {
reentrantLock.unlock();
}
}
}
}
public class Test {
public static void main(String[] args) {
TicketThread thread=new TicketThread();
Thread thread1=new Thread(thread,"窗口1");
Thread thread2=new Thread(thread,"窗口2");
thread1.start();
thread2.start();
}
}
(三)、对比synchronized和ReentrantLock
1、相同点:都能实现加锁的功能
2、不同点:
(1)、synchronized是关键字
ReentrantLock是类
(2)、ReentrantLock只能修饰代码块
synchronized代码块和方法都能修饰
(3)、synchronized可以隐式的加锁和释放锁,运行时如果出现异常能自动释放锁
ReentrantLock需要手动添加和释放,建议在finally代码块中释放