本文共 3886 字,大约阅读时间需要 12 分钟。
java中任何对象默认都会有一个互斥锁标记,用来分配给线程。也可以选择这个所标记 没有分配给任何线程/或者只能给一个线程。 只有拿到对象所标记的线程才能进入到对该对象加锁的同步代码块。 同步锁的是对象 线程退出同步代码块(线程执行完毕 确切来说,run方法执行完毕),会释放相应的锁标记。
synchronized 修饰代码块 对象锁标记 上代码
package com.baigu.demo1.stack;public class TestStack { public static void main(String[] args) throws InterruptedException { Stack stack = new Stack();// stack.print();// stack.posh('C');// stack.print();// stack.pop();// stack.print(); PushThread t1 = new PushThread(stack); PopThread t2 = new PopThread(stack); stack.print(); System.out.println(); t1.start(); t2.start(); Thread.sleep(1000); //睡一秒让t1 t2线程执行结束在执行主线程 stack.print(); }}class Stack{ private char[] data={'A','B',' ',' ',' ',' ',' ',' '}; private int index=2; //记录数组中有效元素的个数 public void posh(char c){ System.out.println(c+" poshed! 入栈"); data[index]=c; try { Thread.sleep(1000); //睡0.1秒类似于时间片到期 } catch (InterruptedException e) { e.printStackTrace(); } index++; } public void pop(){ index --; System.out.println(data[index]+" poped! 出栈"); data[index]=' '; } public void print(){ for (char s:data) System.out.print(s); }}class PushThread extends Thread{ Stack s; public PushThread(Stack s) { this.s = s; } @Override public void run() {// s.posh('C'); synchronized (s){ //同步代码块 参数为对象的引用 对象锁标记 s.posh('C'); } }}class PopThread extends Thread{ Stack s; public PopThread(Stack s) { this.s = s; } @Override public void run() { synchronized (s){ //同步代码块 参数为对象的引用 对象锁标记 s.pop(); } }}
synchronized 修饰方法 方法锁标记 上代码
package com.baigu.demo1.stack;public class Testsynchronizedmethod { public static void main(String[] args) throws InterruptedException { StackTwo stack = new StackTwo(); PushThreadTwo t1 = new PushThreadTwo(stack); PopThreadTwo t2 = new PopThreadTwo(stack); stack.print(); System.out.println(); t1.start(); t2.start(); Thread.sleep(1000); //睡一秒让t1 t2线程执行结束在执行主线程 stack.print(); }}class StackTwo{ private char[] data={'A','B',' ',' ',' ',' ',' ',' '}; private int index=2; //记录数组中有效元素的个数 public synchronized void posh(char c){ //方法锁标记 System.out.println(c+" poshed! 入栈"); data[index]=c; try { Thread.sleep(800); //睡0.1秒类似于时间片到期 } catch (InterruptedException e) { e.printStackTrace(); } index++; } public synchronized void pop(){ //方法锁标记 index --; System.out.println(data[index]+" poped! 出栈"); data[index]=' '; } public void print(){ for (char s:data) System.out.print(s); }}class PushThreadTwo extends Thread{ StackTwo s; public PushThreadTwo(StackTwo s) { this.s = s; } @Override public void run() { s.posh('C'); }}class PopThreadTwo extends Thread{ StackTwo s; public PopThreadTwo(StackTwo s) { this.s = s; } @Override public void run() { s.pop(); }}
synchronized锁机制 无论是同步代码块还是作为修饰符 两种本质相同 下面是做的一些总结
线程同步:当多线程并发访问临界资源(同一个对象)时,多线程同时访问同一个对象时,如果破坏了原子操作(不可分割的操作),就会造成数据不一致。和数据库中的事务类似。1.synchronized(o){}: 对对象o加锁的同步代码块 同步代码块保护原子操作不被破坏。个人理解:主线程运行优于自己创建的线程运行。java中任何对象默认都会有一个互斥锁标记,用来分配给线程。也可以选择这个所标记没有分配给任何线程/或者只能给一个线程。只有拿到对象所标记的线程才能进入到对该对象加锁的同步代码块。同步锁的是对象线程退出同步代码块(线程执行完毕 真正意义上,run方法结束),会释放相应的锁标记。2.synchronized(用作方法修饰符),synchronized修饰的方法叫做同步方法 同步方法指的是在整个方法的范围内对当前对象加锁。只有拿到对象所标记的线程才能调用该对象的同步方法。同步方法等同于同步代码块。锁池:任何对象都有的一个空间,用来存放等待该对象锁标记的线程 (一个或多个)利用锁机制解决线程的同步问题,只有拿到对象所标记的线程才能进入到对该对象加锁的同步代码块(原子操作)。
线程架构图
纠正一点,较之前说的五中状态,现在又增加了一种 锁池状态。这辈子坚持与不坚持都不可怕,怕的是独自走在坚持的道路上。 欢迎加入技术群聊。
转载地址:http://nkoai.baihongyu.com/