synchronized和volatile
volatile :保证内存可见性,但是不保证原子性;
synchronized:同步锁,既能保证内存可见性,又能保证原子性;
synchronized实现可重入锁 (1.持有同一锁自动获取 2.继承锁)
锁定的对象有两种:1.类的实例(对象锁) 2.类对象(类锁)
对象锁(synchronized修饰普通方法或代码块) 对象锁已被其他调用者占用,则需要等待此锁被释放
/**
* 对象锁的两种方式
*/
//方式一
private int count =10;
public synchronized void test01() {
count--;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
//方式二
public void test02() {
synchronized(this) {
count--;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
}
类锁(synchronized修饰静态方法) 所有类实例化对象互斥拥有一把类锁
private static int count =10;
/**
* 类锁两种表现方式
*/
public static synchronized void test01() {
count -- ;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
public static void test02() {
synchronized(CurrentDemo01.class) {
count -- ;
System.out.println(Thread.currentThread().getName()+"count="+count);
}
}
同一字符串常量代表同一把锁对象
//t1执行结束,t2再执行,t1和t2持有同一把锁
public class CurrentDemo03 {
String s1 = "yew";
String s2 = "yew";
public void test01(){
synchronized (s1){
System.out.println(Thread.currentThread().getName()+"---start");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
System.out.println("interrupt");
}
System.out.println(Thread.currentThread().getName()+"---end");
}
}
public void test02(){
synchronized (s2){
System.out.println(Thread.currentThread().getName()+"---start");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("interrupt");
}
System.out.println(Thread.currentThread().getName()+"---end");
}
}
public static void main(String[] args) {
CurrentDemo03 demo3 = new CurrentDemo03();
new Thread(demo3::test01,"t1").start();
new Thread(demo3::test02,"t2").start();
}
}
synchronized同步代码块粒度越小,执行效率越高
public class CurrentDemo04 {
//总数
private static int count = 0;
public synchronized void test01() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"---start");
TimeUnit.SECONDS.sleep(2);
for (int i = 0; i <10000000 ; i++) {
count++ ;
}
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"---end");
}
public void test02() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"---start");
TimeUnit.SECONDS.sleep(2);
synchronized (this){
for (int i = 0; i <10000000 ; i++) {
count++ ;
}
}
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"---end");
}
//demo04.test01();8043ms
// demo04.test02();4116ms
public static void main(String[] args){
CurrentDemo04 demo04 = new CurrentDemo04();
long start = System.currentTimeMillis();
new Thread(new Runnable() {
@Override
public void run() {
try {
demo04.test02();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
demo04.test02();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
System.out.println(Thread.activeCount());
while(Thread.activeCount()>2){
Thread.yield();
}
long end = System.currentTimeMillis();
System.out.println("耗时:"+(end-start)+"ms");
System.out.println(count);
}
}
synchronized方法正常返回或者抛异常而终止,jvm会自动释放对象锁(捕获异常则不会自动释放)
public class CurrentDemo08 {
//总数值
private int count = 0;
public synchronized void test01() throws Exception {
System.out.println(Thread.currentThread().getName()+"---start");
while (true){
count++ ;
TimeUnit.SECONDS.sleep(1);
if(count <5){
System.out.println(count);
}else{
try {
int m = count/0;
}catch (Exception e){
System.out.println("ERROR :"+e.getMessage());
// return;
}
}
}
}
public synchronized void test02() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"----start");
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName()+"---end");
}
public static void main(String[] args) {
CurrentDemo08 demo08 = new CurrentDemo08();
new Thread(()-> {
try {
demo08.test01();
} catch (Exception e) {
System.out.println("test01中断");
}
},"t1").start();
new Thread(()-> {
try {
demo08.test02();
} catch (InterruptedException e) {
System.out.println("test02中断");
}
},"t2").start();
}
}
/**
* @author yew
* @date on 2019/11/18 - 11:49
* 一道面试题:实现一个容器,提供两个方法,add,size
* 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,
* 当个数到5个时,线程2给出提示并结束线程2
* 1.无volatile,线程间不可见,线程t2不会结束
* 2.volatile可以保证原子的可见性,存在不确定性 while(true) 占用CPU资源
*/
public class CurrentDemo11 {
//List<Object> lists = new ArrayList<Object>();
volatile List<Object> lists = new ArrayList<Object>();
public void add(Object s) {
lists.add(s);
}
public int size() {
return lists.size();
}
public static void main(String[] args) {
CurrentDemo11 demo11 = new CurrentDemo11();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
demo11.add(new Object());
System.out.println("add Object" + (i + 1));
try {
TimeUnit.MILLISECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("t1线程结束");
}, "t1").start();
new Thread(() -> {
System.out.println("t2线程开始");
while (true) {
if (demo11.size() == 5){
break;
}
}
System.out.println("t2线程结束");
}, "t2").start();
}
}优化上述问题:
/** * @author yew * 1.wait----notify(随机唤醒持有当前锁且等待的某个线程)/notifyAll(唤醒持有当前锁所有的等待线程) * notify随机唤醒持有锁等待的线程,但是不会释放当前持有的锁 所以监控线程不会立马结束 * 2.countdownLatch */public class CurrentDemo12 { List lists = new ArrayList(); public int size() { return this.lists.size(); } public void add(Object obj) { this.lists.add(obj); } public static void main(String[] args) { CurrentDemo12 demo12 = new CurrentDemo12(); Object lock = new Object(); //先启用t2进行监听 new Thread(()->{ synchronized (lock){ System.out.println("t2线程启动"); if(demo12.size() != 5){ try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("t2线程结束"); lock.notify(); } },"t2").start(); new Thread(()->{ synchronized (lock){ System.out.println("t1线程启动"); for (int i = 0; i < 10 ; i++) { System.out.println("add Object"+(i+1)); demo12.add(new Object()); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } if(demo12.size() == 5){ lock.notify(); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } System.out.println("t1线程结束"); } }).start(); }}
/** * 面试题:写一个固定容量同步容器,拥有Put和get方法,以及getCount方法,
* 能够支持两个生产者线程以及10个消费者线程的阻塞调用
* wait notifyAll
*/
public class CurrentDemo13 {
private static final int MAX = 20;
private final LinkedList<Object> list = new LinkedList<>();
static int count;
public synchronized void put(Object obj){
while (list.size() == MAX){
try {
this.wait();
} catch (InterruptedException e) {
System.out.println();
}
}
list.add(obj);
++count;
System.out.println("生产后剩余数量"+count);
this.notifyAll();
}
public synchronized Object get(){
while (list.size()==0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Object t = list.removeFirst();
--count;
System.out.println("消费后剩余数量"+count);
this.notifyAll();
return t;
}
public int getCount(){
return count;
}
public static void main(String[] args) {
CurrentDemo13 demo13 = new CurrentDemo13();
//创建生产者
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
while (true){
demo13.put(Thread.currentThread().getName()+"---"+count);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println(demo13.get());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
}
/** * condition:在某种状态下 */public class CurrentDemo14 { LinkedList<Object> lists = new LinkedList<>(); private static final int MAX = 20; private static int count = 0; ReentrantLock lock = new ReentrantLock(); Condition producer = lock.newCondition(); Condition consumer = lock.newCondition(); public void put(Object obj){ try { lock.lock(); while (lists.size()==MAX){ producer.await(); } lists.add(obj+"----"+count); count++; System.out.println("生产后剩余:"+count); Thread.sleep(500); consumer.signalAll(); } catch (Exception e) { System.out.println("生产线程异常中断"+e.getMessage()); }finally { lock.unlock(); } } public Object get(){ Object t = null; try { lock.lock(); while (lists.size()==0){ consumer.await(); } t = lists.removeFirst(); System.out.println("已消费对象:"+t); count--; System.out.println("消费后剩余:"+count); Thread.sleep(2000); producer.signalAll(); } catch (Exception e) { System.out.println("消费线程异常中断"+e.getMessage()); }finally { lock.unlock(); return t; } } public static void main(String[] args){ CurrentDemo14 currentDemo14 = new CurrentDemo14(); for (int i = 0; i < 2; i++) { new Thread("p"+i){ public void run(){ for (;;) { currentDemo14.put(Thread.currentThread().getName()); } } }.start(); } try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } for (int i = 0; i < 10; i++) { new Thread("c"+i){ public void run(){ for (;;) { currentDemo14.get(); } } }.start(); } }}
/**
* ReentrantLock
* ReentrantLock同synchronized效果相同
* 1.synchronized遇到异常,自动释放锁,reentranLock需要手动释放锁,所以释放锁需要放在finally代码块执行;
* 2.tryLock() 尝试拿锁,拿不到锁的时候可以根据返回的boolean值来决定是否继续执行
* 3.lockInterruptibly()可以对线程中断做出反应
*/
public class CurrentDemo15 {
ReentrantLock lock = new ReentrantLock();
public void test01(){
try{
lock.lock();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"test 01");
int t = 10/0;
}catch (Exception e){
System.out.println("ERROR");
}finally {
lock.unlock();
}
}
public void test02(){
try{
// lock.tryLock(3, TimeUnit.SECONDS);
// lock.lockInterruptibly();
lock.lock();
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()+"test 02");
}catch (Exception e){
System.out.println("ERROR");
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
CurrentDemo15 currentDemo15 = new CurrentDemo15();
new Thread("t1"){
public void run(){
currentDemo15.test01();
}
}.start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread t2 = new Thread("t2"){
public void run(){
currentDemo15.test02();
}
};
t2.start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.interrupt();
}
}
来源:https://www.cnblogs.com/vincentYw/p/11834793.html