黑馬程式設計師多執行緒視訊總結
執行緒池的工作模型主要兩部分組成,一部分是執行Runnable的Thread物件,另一部分就是阻塞佇列。
由執行緒池建立的Thread物件其內部的run方法會通過阻塞佇列的take方法獲取一個Runnable物件,然後執行這個Runnable物件的run方法(即,在Thread的run方法中呼叫Runnable物件的run方法)。當Runnable物件的run方法執行完畢以後,Thread中的run方法又迴圈的從阻塞佇列中獲取下一個Runnable物件繼續執行。這樣就實現了Thread物件的重複利用,也就減少了建立執行緒和銷燬執行緒所消耗的資源。
當需要向執行緒池提交任務時會呼叫阻塞佇列的offer方法向佇列的尾部新增任務。提交的任務實際上就是是Runnable物件或Callable物件。
1.執行緒範圍共享變數
public class ThreadScopeShareData {
private static int data = 0; private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>(); public static void main(String[] args) { for(int i=0;i<2;i++){ new Thread(new Runnable(){ @Override public void run() { int data = new Random().nextInt(); System.out.println(Thread.currentThread().getName() + " has put data :" + data); //threadData.put(Thread.currentThread(), data); threadData.set(data);//這樣寫即可 new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ int data = threadData.get(Thread.currentThread()); System.out.println("A from " + Thread.currentThread().getName() + " get data :" + data); } } static class B{ public void get(){ int data = threadData.get(Thread.currentThread()); System.out.println("B from " + Thread.currentThread().getName() + " get data :" + data); } }
}
2.TreadLocal實現執行緒範圍共享變數
public class ThreadLocalTest {
//一個TreadLocal只能代表一個變數,要是有多個數據需要線上程範圍共享就要有多個TreadLocal,或者弄成類
private static ThreadLocal x = new ThreadLocal();
private static ThreadLocal myThreadScopeData = new ThreadLocal();
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable(){
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()
+ ” has put data :” + data);
x.set(data);
/*MyThreadScopeData myData = new MyThreadScopeData();
myData.setName("name" + data);
myData.setAge(data);
myThreadScopeData.set(myData);*/
MyThreadScopeData.getThreadInstance().setName("name" + data);
MyThreadScopeData.getThreadInstance().setAge(data);
new A().get();
new B().get();
}
}).start();
}
}
static class A{
public void get(){
int data = x.get();
System.out.println("A from " + Thread.currentThread().getName()
+ " get data :" + data);
/*MyThreadScopeData myData = myThreadScopeData.get();;
System.out.println("A from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + "," +
myData.getAge());*/
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("A from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + "," +
myData.getAge());
}
}
static class B{
public void get(){
int data = x.get();
System.out.println("B from " + Thread.currentThread().getName()
+ " get data :" + data);
//得到當前執行緒的物件
MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("B from " + Thread.currentThread().getName()
+ " getMyData: " + myData.getName() + "," +
myData.getAge());
}
}
}
class MyThreadScopeData{
//按照單例相似的去寫優雅的方式
private MyThreadScopeData(){}
//不用synchronized因為一個執行緒對應修改get set自己的變數
public static /synchronized/ MyThreadScopeData getThreadInstance(){
MyThreadScopeData instance = map.get();
if(instance == null){
instance = new MyThreadScopeData();
map.set(instance);
}
return instance;
}
//private static MyThreadScopeData instance = null;//new MyThreadScopeData();
private static ThreadLocal map = new ThreadLocal();
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;
}
}
3.多執行緒訪問共享物件和資料的方法
如果每個執行緒執行的程式碼相同,可用同一個Runnable物件,Runnable中由共享資料(例如賣票)
如果每個執行緒執行的程式碼不同,可將共享資料封裝在另一個物件中,然後將這個物件逐一傳遞給各Runnable
public class MultiThreadShareData {
private static ShareData1 data1 = new ShareData1();
public static void main(String[] args) {
ShareData1 data2 = new ShareData1();
new Thread(new MyRunnable1(data2)).start();
new Thread(new MyRunnable2(data2)).start();
final ShareData1 data1 = new ShareData1();
new Thread(new Runnable(){
@Ov erride
public void run() {
data1.decrement();
}
}).start();
new Thread(new Runnable(){
@Override
public void run() {
data1.increment();
}
}).start();
}
}
class MyRunnable1 implements Runnable{
private ShareData1 data1;
public MyRunnable1(ShareData1 data1){
this.data1 = data1;
}
public void run() {
data1.decrement();
}
}
class MyRunnable2 implements Runnable{
private ShareData1 data1;
public MyRunnable2(ShareData1 data1){
this.data1 = data1;
}
public void run() {
data1.increment();
}
}
class ShareData1 /*implements Runnable*/{
/* private int count = 100;
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
count–;
}
}*/
private int j = 0;
public synchronized void increment(){
j++;
}
public synchronized void decrement(){
j--;
}
}
java5之後:
4.原子類:AtomicInteger AtomicIntegerArray 。。。應用於多執行緒共享的資料
5.tomcat伺服器中
new Thread(){
while(池子中還有執行緒需要接待){
和執行緒聊一會;
}
}.start();
執行緒池
public class ThreadPoolTest {
public static void main(String[] args) {
//ExecutorService threadPool = Executors.newFixedThreadPool(3); 固定數目的執行緒池,3個3個搶佔資源
//ExecutorService threadPool = Executors.newCachedThreadPool(); 數目動態變化的執行緒池,來多少執行緒池多大
ExecutorService threadPool = Executors.newSingleThreadExecutor();單一執行緒池,如何實現執行緒死了後重新啟動,當一個執行緒死了後,會馬上找一個替補的執行緒
for(int i=1;i<=10;i++){
final int task = i;
threadPool.execute(new Runnable(){
@Override
public void run() {
for(int j=1;j<=10;j++){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " is looping of " + j + " for task of " + task);
}
}
});
}
System.out.println("all of 10 tasks have committed! ");
//threadPool.shutdownNow();
//定時器
Executors.newScheduledThreadPool(3).scheduleAtFixedRate(
new Runnable(){
@Override
public void run() {
System.out.println("bombing!");
}},
6,
2,
TimeUnit.SECONDS);
}
}
6.
public class CallableAndFuture {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();
Future future =
threadPool.submit( ——提交一個返回值
new Callable() {
public String call() throws Exception {
Thread.sleep(2000);
return “hello”;
};
}
);
System.out.println(“等待結果”);
try {
System.out.println(“拿到結果:” + future.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//CompletionService用於提交一組Callable任務,take方法返回已完成的Callable任務對應的furtuer物件
ExecutorService threadPool2 = Executors.newFixedThreadPool(10);
CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(threadPool2);
//提交10個任務
for(int i=1;i<=10;i++){
final int seq = i;
completionService.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
Thread.sleep(new Random().nextInt(5000));
return seq;
}
});
}
//拿到10個結果
for(int i=0;i<10;i++){
try {
System.out.println(
completionService.take().get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
7.讀寫鎖:讀寫互斥,寫寫互斥,讀讀沒事
鎖比synchronized更加面向物件,必須要再結尾finnal中釋放鎖
public class ReadWriteLockTest {
public static void main(String[] args) {
final Queue3 q3 = new Queue3();
for(int i=0;i<3;i++)
{
new Thread(){
public void run(){
while(true){
q3.get();
}
}
}.start();
new Thread(){
public void run(){
while(true){
q3.put(new Random().nextInt(10000));
}
}
}.start();
}
}
}
class Queue3{
private Object data = null;//共享資料,只能有一個執行緒能寫該資料,但可以有多個執行緒同時讀該資料。
ReadWriteLock rwl = new ReentrantReadWriteLock();
public void get(){
rwl.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + ” be ready to read data!”);
Thread.sleep((long)(Math.random()*1000));
System.out.println(Thread.currentThread().getName() + “have read data :” + data);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
rwl.readLock().unlock();
}
}
public void put(Object data){
rwl.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " be ready to write data!");
Thread.sleep((long)(Math.random()*1000));
this.data = data;
System.out.println(Thread.currentThread().getName() + " have write data: " + data);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
rwl.writeLock().unlock();
}
}
}
8.模擬快取
這樣寫讀寫效率高
public class CacheDemo {
//內部定義一個map
private Map