线程安全概念:当多个线程访问某一个类(对象或方法)时,这个对象始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。
synchronized:可以在任意对象及方法上加锁,而加锁的这段代码称为"互斥区"或"临界区"
public class MyThread  extends  Thread{

    private int count = 5 ;
public void run() {
count--;
System.out.println(this.currentThread().getName() + " count = " + count);
}
public static void main(String[] args) {
/**
* 分析:当多个线程访问myThread的run方法时,以排队的方式进行处理(这里排对是按照CPU分配的先后顺序而定的),
* 一个线程想要执行synchronized修饰的方法里的代码:
* 1 尝试获得锁
* 2 如果拿到锁,执行synchronized代码体内容;拿不到锁,这个线程就会不断的尝试获得这把锁,直到拿到为止,
* 而且是多个线程同时去竞争这把锁。(也就是会有锁竞争的问题)
*/
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread,"t1");
Thread t2 = new Thread(myThread,"t2");
Thread t3 = new Thread(myThread,"t3");
Thread t4 = new Thread(myThread,"t4");
Thread t5 = new Thread(myThread,"t5");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}

  

同步:synchronized 同步的概念就是共享锁,不是共享的资源就没必要进行同步。

异步:asynchronized 相互之间不受到制约。

同步的目的就是为了线程安全,需要满足两个特性:

1.原子性

2.可见性

对象锁的同步和异步问题

public class MyObject {
public synchronized void method1(){
try{
System.out.println(Thread.currentThread().getName());
Thread.sleep(4000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
public void method2(){
System.out.println(Thread.currentThread().getName());
} public static void main(String[] args) {
final MyObject mo=new MyObject();
/**
* 分析:
* t1线程先持有object对象的Lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法
* t1线程先持有object对象的Lock锁,t2线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步
*/
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
mo.method1();
}
},"t1"); Thread t2=new Thread(new Runnable() {
@Override
public void run() {
mo.method2();
}
},"t2"); t1.start();
t2.start();
}
}

  对于对象的同步和异步方法,设计程序,一定要考虑问题的整体,不然就会出现数据不一致的情况。脏读(dirtyread)

public class DirtyRead {
private String username = "laoshi";
private String password = "123"; public synchronized void setValue(String username, String password){
this.username = username; try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} this.password = password; System.out.println("setValue最终结果:username = " + username + " , password = " + password);
} public void getValue(){
System.out.println("getValue方法得到:username = " + this.username + " , password = " + this.password);
} public static void main(String[] args) throws Exception{ final DirtyRead dr = new DirtyRead();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
dr.setValue("laosun", "456");
}
});
t1.start();
Thread.sleep(1000); dr.getValue();
}
}

  

要枷锁,一起枷锁。不加都不加,保证业务的原子性。

synchronized锁重入:
当一个线程得到一个对象的锁后,再次请求对象可以再次得到对象的锁
public class SyncDubbo1 {

    public synchronized void method1(){
System.out.println("method1..");
method2();
}
public synchronized void method2(){
System.out.println("method2..");
method3();
}
public synchronized void method3(){
System.out.println("method3..");
} public static void main(String[] args) {
final SyncDubbo1 sd = new SyncDubbo1();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
sd.method1();
}
});
t1.start();
}
}

  

public class SyncDubbo2 {
static class Main {
public int i = 10;
public synchronized void operationSup(){
try {
i--;
System.out.println("Main print i = " + i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} static class Sub extends Main {
public synchronized void operationSub(){
try {
while(i > 0) {
i--;
System.out.println("Sub print i = " + i);
Thread.sleep(100);
this.operationSup();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) { Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
Sub sub = new Sub();
sub.operationSub();
}
}); t1.start();
}
}

  synchronized异常

public class SyncException {
private int i = 0;
public synchronized void operation(){
while(true){
try {
i++;
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " , i = " + i);
if(i == 20){
//Integer.parseInt("a");
throw new RuntimeException();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) { final SyncException se = new SyncException();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
se.operation();
}
},"t1");
t1.start();
}
}

  锁对象的改变问题

public class ChangeLock {
private String lock = "lock"; private void method(){
synchronized (lock) {
try {
System.out.println("当前线程 : " + Thread.currentThread().getName() + "开始");
lock = "change lock";
Thread.sleep(2000);
System.out.println("当前线程 : " + Thread.currentThread().getName() + "结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) { final ChangeLock changeLock = new ChangeLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
changeLock.method();
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
changeLock.method();
}
},"t2");
t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}

  死锁问题,在设计程序时就应该避免双方相互持有对方的锁的情况

public class DeadLock implements Runnable{
private String tag;
private static Object lock1 = new Object();
private static Object lock2 = new Object(); public void setTag(String tag){
this.tag = tag;
} @Override
public void run() {
if(tag.equals("a")){
synchronized (lock1) {
try {
System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock1执行");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock2执行");
}
}
}
if(tag.equals("b")){
synchronized (lock2) {
try {
System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock2执行");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock1执行");
}
}
}
} public static void main(String[] args) { DeadLock d1 = new DeadLock();
d1.setTag("a");
DeadLock d2 = new DeadLock();
d2.setTag("b"); Thread t1 = new Thread(d1, "t1");
Thread t2 = new Thread(d2, "t2"); t1.start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}

  

同一对象属性的修改不会影响锁的情况
public class ModifyLock {
private String name ;
private int age ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public synchronized void changeAttributte(String name, int age) {
try {
System.out.println("当前线程 : " + Thread.currentThread().getName() + " 开始");
this.setName(name);
this.setAge(age); System.out.println("当前线程 : " + Thread.currentThread().getName() + " 修改对象内容为: "
+ this.getName() + ", " + this.getAge()); Thread.sleep(2000);
System.out.println("当前线程 : " + Thread.currentThread().getName() + " 结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
final ModifyLock modifyLock = new ModifyLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
modifyLock.changeAttributte("张三", 20);
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
modifyLock.changeAttributte("李四", 21);
}
},"t2"); t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
使用synchronized代码块加锁,比较灵活
public class ObjectLock {
public void method1(){
synchronized (this){//对象锁
try {
System.out.println("do method1..");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void method2(){ //类锁
synchronized (ObjectLock.class){
try {
System.out.println("do method2..");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private Object lock=new Object();
public void method3(){ //任何对象锁
synchronized (lock){
try {
System.out.println("do method3..");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) { final ObjectLock objLock = new ObjectLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
objLock.method1();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
objLock.method2();
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
objLock.method3();
}
}); t1.start();
t2.start();
t3.start();
}
}

  使用synchronized代码块减小锁的粒度,提高性能

public class Optimize {
public void doLongTimeTask(){
try { System.out.println("当前线程开始:" + Thread.currentThread().getName() +
", 正在执行一个较长时间的业务操作,其内容不需要同步");
Thread.sleep(2000); synchronized(this){
System.out.println("当前线程:" + Thread.currentThread().getName() +
", 执行同步代码块,对其同步变量进行操作");
Thread.sleep(1000);
}
System.out.println("当前线程结束:" + Thread.currentThread().getName() +
", 执行完毕"); } catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
final Optimize otz = new Optimize();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
otz.doLongTimeTask();
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
otz.doLongTimeTask();
}
},"t2");
t1.start();
t2.start();
}
}

  

synchronized代码块对字符串的锁,注意String常量池的缓存功能
public class StringLock {
public void method(){
synchronized ("字符串常量") {
try {
while(true){
System.out.println("当前线程 : " + Thread.currentThread().getName() + "开始");
Thread.sleep(1000);
System.out.println("当前线程 : " + Thread.currentThread().getName() + "结束");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final StringLock stringLock = new StringLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
stringLock.method();
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
stringLock.method();
}
},"t2"); t1.start();
t2.start();
}
}

  

最新文章

  1. 使用AngularJS实现简单:全选和取消全选功能
  2. PostgreSQL入门
  3. html表格相关
  4. CCNA网络工程师学习进程(6)vlan相关协议的配置与路由器简单配置介绍
  5. SpringMvc出现No mapping found for HTTP request with URI的终极解决办法
  6. 【转】Vim十大必备插件
  7. 基于进程的Quartz.NET管理系统QuartzService(一)
  8. ZOJ2006 (最小表示法)
  9. 存储过程往拼接的sql语句中传递日期值
  10. uva 1391 Astronauts(2-SAT)
  11. LeetCode_Unique Paths
  12. 深入浅出—JAVA(2)
  13. css3选择器:nth-child和nth-of-type之间的差别
  14. The POM for * is invalid
  15. mysql中text数据类型
  16. 1053. Path of Equal Weight (30)
  17. 正则检查是否为IP地址
  18. Java基础【基本数据类型包装类、int与String 之间的相互转换】
  19. linux basic ------ shell
  20. Oracle数据库通过DBLINK实现远程访问

热门文章

  1. pycharm+gitee【代码上传下载】实战(windows详细版)
  2. 缺陷的优先程度(Priority)
  3. 解决WordPress访问中文标签出现404的几个方法
  4. python3中Requests将verify设置为False后,取消警告的方式
  5. 刷题记录:2018HCTF&admin
  6. magento2重写virtualType并且传参
  7. 查看DDR的频率【学习笔记】
  8. func 传参异步方法
  9. electron---表单验证问题
  10. 微信公众号开发系统入门教程(公众号注册、开发环境搭建、access_token管理、Demo实现、natapp外网穿透)