目录
2.1.1.同步非static的 synchronized方法---对象锁
2.1.2.同步代码块 synchronized (this)---对象锁
2.1.3.同步方法及static的synchronized方法---类锁
2.1.4synchronized(类.class)----类锁
1.为什么需要线程同步?
观察以下代码的结果:
class MyThread implements Runnable {
private int ticket = 10;
@Override
public void run() {
for (int i = 0; i <= 10; i++) {
{
if (this.ticket > 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 模拟网络延迟
System.out.println(Thread.currentThread().getName() + ",还有" + this.ticket-- + " 张票");
}
}
}
}
}
public class test {
public static void main(String[] args) {
MyThread myTread = new MyThread();
Thread T1 = new Thread(myTread, "黄牛1");
Thread T2 = new Thread(myTread, "黄牛2");
Thread T3 = new Thread(myTread, "黄牛3");
T1.start();
T2.start();
T3.start();
}
}
结果:

这时候看到结果中负数,这种就是不同步操作,多线程并发执行导致的,唯一的好处就是处理速度快。
2.同步处理
2.1synchronized处理同步问题
所谓的同步指的是所有的线程不是一起进入到方法中执行,而是按照顺序一个一个进来。

2.1.1.同步非static的 synchronized方法---对象锁
要使用同步代码块必须设置一个要锁定的对象,所以一般可以锁定当前对象:this,以下实例是一个实例划对象
import static java.lang.Thread.sleep;
//同步方法
class testThread implements Runnable
{
private int ticket=100;
@Override
public void run() {
for (int i=0;i<100;i++)
{
try {
this.sale();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void sale() throws InterruptedException {
if (this.ticket>0)
{
sleep(20);
System.out.println(Thread.currentThread().getName()+":还有"+this.ticket--+"张票");
}
}
}
public class demo {
public static void main(String[] args) {
testThread thread=new testThread();
Thread thread1=new Thread(thread,"黄牛1");
Thread thread2=new Thread(thread, "黄牛2");
thread1.start();
thread2.start();
}
}
2.1.2.同步代码块 synchronized (this)---对象锁
但是同步方法是在方法里拦截的,也就是说进入到方法中的线程依然可能会有多个。
class MyTread implements Runnable
{
private int ticket=10;
@Override
public void run() {
for (int i = 0; i <=10; i++) {
synchronized (this) {
if (this.ticket > 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 模拟网络延迟
System.out.println(Thread.currentThread().getName() + ",还有" + this.ticket-- + " 张票");
}
}
}
}
}
实际上,synchronized(this)以及非static的synchronized方法,只能防止多个线程同时执行同一个对象的同步代码 段。即synchronized锁住的是括号里的对象,而不是代码。对于非static的synchronized方法,锁的就是对象本身也 就是this。
2.1.3.同步方法及static的synchronized方法---类锁
import static java.lang.Thread.sleep;
class MyThread implements Runnable {
// private int ticket = 10;
@Override
public void run() {
try {
MyThread.fun();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static synchronized void fun() throws InterruptedException {
System.out.println("加锁的方法开始执行");
System.out.println(Thread.currentThread().getName());
sleep(200);
System.out.println("加锁的方法执行结束");
}
}
2.1.4synchronized(类.class)----类锁
class MyThread implements Runnable
{
private int ticket=10;
@Override
public void run() {
for (int i = 0; i <=10; i++) {
synchronized (MyThread.class) {
if (this.ticket > 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 模拟网络延迟
System.out.println(Thread.currentThread().getName() + ",还有" + this.ticket-- + " 张票");
}
}
}
}
}
2.1.5synchronized(object)--类锁
2.2Lock锁
JDK1.5提供的Lock锁
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static java.lang.Thread.currentThread;
import static java.lang.Thread.sleep;
class MyReenrantLock implements Runnable
{
private Lock numLock=new ReentrantLock();
@Override
public void run() {
for (int i=1;i<10;i++)
{
//加锁
numLock.lock();
System.out.println(Thread.currentThread().getName()+":还有"+i+"人");
//释放锁
numLock.unlock();
}
}
}
public class demo {
public static void main(String[] args) {
MyReenrantLock myTread=new MyReenrantLock();
Thread T1= new Thread(myTread,"线程1");
Thread T2= new Thread(myTread,"线程2");
Thread T3=new Thread(myTread,"线程3");
T1.start();
T2.start();
T3.start();
}
}
在JDK1.5中,synchronized是性能低效的。因为这是一个重量级操作,它对性能最大的影响是阻塞的是实现,挂起 线程和恢复线程的操作都需要转入内核态中完成,这些操作给系统的并发性带来了很大的压力。相比之下使用Java 提供的Lock对象,性能更高一些。 到了JDK1.6,发生了变化,对synchronize加入了很多优化措施,有自适应自旋,锁消除,锁粗化,轻量级锁,偏向 锁等等。导致在JDK1.6上synchronize的性能并不比Lock差。官方也表示,他们也更支持synchronized,在未来的版 本中还有优化余地,所以还是提倡在synchronized能实现需求的情况下,优先考虑使用synchronized来进行同步。
3.俩个重要问题:
1.对象锁和类锁的区别
- 1.对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。
- 2.使用对象锁的情况,只有使用同一实例的线程才会受锁的影响,多个实例调用同一方法也不会受影响,类锁是加载类上的,而类信息是存在 JVM 方法区的,并且整个 JVM 只有一份,方法区又是所有线程共享的,所以类锁是所有线程共享的。
2.Lock锁和synchronized的区别
- 1.synchronized无法判断是否获取锁的状态,Lock手动获取到锁;
- 2.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
- 3.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
- 4.lock是一个接口,而synchronized是java的一个关键字,synchronized是内置的语言实现;

本文详细介绍了线程同步的必要性及实现方式,包括synchronized关键字的多种应用方式和Lock接口的使用方法,并对比了对象锁与类锁的区别,以及Lock锁与synchronized锁的不同之处。
3944

被折叠的 条评论
为什么被折叠?



