并发编程(一)—— 线程基础

1.1 基础

一、概念

线程安全概念:当多个线程访问某一个类(对象或方法)时,这个类始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。

二、synchronized

可以在任意对象及方法上加锁,而加锁的这段代码称为“互斥区”或“临界区”。

三、示例

【com.xxy.thread01】My Thread

 1 package com.xxy.thread01;
 2 
 3 public class MyThread extends Thread{
 4     private int count = 5;
 5     
 6     public synchronized void run() {
 7         count--;
 8         System.out.println(this.currentThread().getName() + " count=" + count);
 9     }
10     
11     public static void main(String[] args) {
12         /*
13          * 分析:当多个线程访问myThread的run方法时,以排队的方式进行处理(这里排队是按照CPU分配的先后顺序而定的)
14          *      一个线程想要执行synchronized修饰的方法里的代码:
15          *      1. 尝试获得锁
16          *      2. 如果拿到锁,执行synchronized代码体内容;拿不到锁,这个线程会不断的尝试获得这把锁,直到拿到为止。
17          *         而且是多个线程同时去竞争这把锁(这就是会有锁竞争的问题)。 
18          */
19         MyThread myThread = new MyThread();
20         Thread t1 = new Thread(myThread, "t1");
21         Thread t2 = new Thread(myThread, "t2");
22         Thread t3 = new Thread(myThread, "t3");
23         Thread t4 = new Thread(myThread, "t4");
24         Thread t5 = new Thread(myThread, "t5");
25         t1.start();
26         t2.start();
27         t3.start();
28         t4.start();
29         t5.start();
30     }
31 }
View Code

四、示例总结

当多个线程访问My Thread的run方法时,以排队的方式进行处理(这里排队是按照CPU分配的先后顺序而定的),一个线程想要执行synchronized修饰的方法里的代码,首先是尝试获得锁,如果拿到锁,执行synchronized代码体内容:拿不到锁,这个线程就会不断的尝试获得这把锁,直到拿到为止,而且是多个线程同时去竞争这把锁。(也就是会有锁竞争的问题)。

 1.2 多个线程多个锁

一、概念

多个线程多个锁:多个线程,每个线程都可以拿到自己指定的锁,分别获得锁之后,执行synchronized方法体的内容。

二、示例:【com.xxy.sync002】MultiThread

 1 package com.xxy.thread01;
 2 
 3 public class MultiThread {
 4     /*static*/
 5     private int number = 0;
 6     /*static*/
 7     public synchronized void print(String tag){
 8         if(tag.equals("a")) {
 9             number = 100;
10             System.out.println("tag a set over");
11             try {
12                 Thread.sleep(1000);
13             } catch (InterruptedException e) {
14                 // TODO Auto-generated catch block
15                 e.printStackTrace();
16             }
17         } else {
18             number = 200;
19             System.out.println("tab b set over");
20         }
21         System.out.println("tag "+ tag +"number = " + number);
22     }
23     
24     public static void main(String[] args) {
25         final MultiThread m1 = new MultiThread();
26         final MultiThread m2 = new MultiThread();
27         
28         Thread t1 = new Thread(new Runnable() {
29             
30             @Override
31             public void run() {
32                 m1.print("a");
33             }
34         });
35         
36         Thread t2 = new Thread(new Runnable() {
37             
38             @Override
39             public void run() {
40                 m2.print("b");
41             }
42         });
43         
44         t1.start();
45         t2.start();
46     }
47 }
View Code

三、示例总结

关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当作锁,所以示例代码中哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock),两个对象,线程获得的就是两个不同的锁,他们互不影响。有一种情况则是相同的锁,即在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class)

1.3 对象锁的同步和异步

一、概念

同步:synchronized

同步的概念就是共享,我们要牢牢记住“共享”这两个字,如果不是共享的资源,就没有必要进行同步。

异步:asynchronized

异步的概念就是独立,相互之间不受任何制约。就好像我们学习http的时候,在页面发起的Ajax请求,我们还可以继续浏览或操作页面的内容,两者之间没有任何关系。

同步的目的就是为了线程安全,其实对于线程来说,需要满足两个特性:原子性(同步)、可见性。

二、示例【com.xxy.sync003】MyObject

 1 package com.xxy.thread01;
 2 
 3 public class MyObject {
 4     public synchronized void method1() {
 5         try {
 6             System.out.println(Thread.currentThread().getName());
 7             Thread.sleep(4000);
 8         } catch (InterruptedException e) {
 9             // TODO Auto-generated catch block
10             e.printStackTrace();
11         }
12     }
13     
14     //synchronized
15     public void method2() {
16         System.out.println(Thread.currentThread().getName());
17     }
18     
19     public static void main(String[] args) {
20         final MyObject mo = new MyObject();
21         /**
22          * 分析:
23          * t1线程先持有MyObject对象的Lock锁,t2线程可以以异步的方式调用对象中的非synchronized修饰的方法。
24          * t1线程先持有MyObject对象的Lock锁,t2线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步。
25          */
26         Thread t1 = new Thread(new Runnable() {
27             
28             @Override
29             public void run() {
30                 mo.method1();
31             }
32         }, "t1");
33         
34         Thread t2 = new Thread(new Runnable() {
35             
36             @Override
37             public void run() {
38                 mo.method2();
39             }
40         }, "t2");
41         
42         t1.start();
43         t2.start();
44     }
45 }
View Code

三、示例总结:

A线程先持有Object对象的Lock锁,B线程如果在这个时候调用对象中的同步(synchronized)方法则需等待,也就是同步。

A线程现持有Object对象的Lock锁,B线程可以以异步的方式调用对象中的非synchronized修饰的方法。

原文地址:https://www.cnblogs.com/upyang/p/13642798.html