線程:整理

一:線程概述

1,進程:正在運行的程序,是系統進行資源分配和調用的獨立單位。每一個進程都有它自己的內存空間和系統資源。

2,線程:是進程中的單個順序控制流,是一條執行路徑一個進程如果只有一條執行路徑,則稱爲單線程程序。一個進程如果有多條執行路徑,則稱爲多線程程序。

二:線程的實現:

 1,方式一:

編寫一個類繼承Thread類

重寫run()方法

線程

線程類:

public class MyThread extends Thread {
	@Override
	public void run() {
		for (int x = 0; x < 200; x++) {
			System.out.println(x);
		}
	}
}

測試類:

public class MyThreadDemo {
	public static void main(String[] args) {
		MyThread my1 = new MyThread();
		MyThread my2 = new MyThread();
		my1.start();
		my2.start();
	}
}

a,注意:

           run和start的區別:

                run():僅僅是封裝被線程執行的代碼,直接調用是普通方法

                start():首先啓動了線程,然後再由jvm去調用該線程的run()方法。

b,爲什麼要重寫run方法

            不是類中的所有代碼都需要被線程執行的。而這個時候,爲了區分哪些代碼能夠被線程執行,java提供了Thread                 類中的run()用來包含那些被線程執行的代碼。

            C:創建對象

            D:啓動線程

c,線程名的獲取和設置

         設置名稱: public final String setName()或者構造方法來設置線程的名稱。

          獲取名稱:

               public final String getName():獲取線程的名稱。

               public static Thread currentThread():返回當前正在執行的線程對象

d,線程優先級

      線程優先級默認爲5,範圍爲1至10;

通過:

           public final int getPriority()

獲取優先級

通過:

           public final void setPriority(int newPriority)

設置優先級別

e,線程控制

 線程休眠
         public static void sleep(long millis)

public class ThreadSleepDemo {
	public static void main(String[] args) {
		ThreadSleep ts1 = new ThreadSleep();
		ThreadSleep ts2 = new ThreadSleep();
		ThreadSleep ts3 = new ThreadSleep();
 
		ts1.setName("林青霞");
		ts2.setName("林志玲");
		ts3.setName("林志穎");
 
		ts1.start();
		ts2.start();
		ts3.start();
	}
}
public class ThreadSleep extends Thread {
	@Override
	public void run() {
		for (int x = 0; x < 100; x++) {
			System.out.println(getName() + ":" + x + ",日期:" + new Date());
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}


        
  加入線程
        public final void join():等待該線程終止。 
        

public class ThreadJoinDemo {
	public static void main(String[] args) {
		ThreadJoin tj1 = new ThreadJoin();
		ThreadJoin tj2 = new ThreadJoin();
		ThreadJoin tj3 = new ThreadJoin();
 
		tj1.setName("李淵");
		tj2.setName("李世民");
		tj3.setName("李元霸");
 
		tj1.start();
		try {
			tj1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		tj2.start();
		tj3.start();
	}
}
public class ThreadJoin extends Thread {
	@Override
	public void run() {
		for (int x = 0; x < 100; x++) {
			System.out.println(getName() + ":" + x);
		}
	}
}


  禮讓線程
        public static void yield():暫停當前正在執行的線程對象,並執行其他線程。 
        讓多個線程的執行更和諧,但是不能靠它保證一人一次。

public class ThreadYieldDemo {
	public static void main(String[] args) {
		ThreadYield ty1 = new ThreadYield();
		ThreadYield ty2 = new ThreadYield();
 
		ty1.setName("林青霞");
		ty2.setName("劉意");
 
		ty1.start();
		ty2.start();
	}
}
public class ThreadYield extends Thread {
	@Override
	public void run() {
		for (int x = 0; x < 100; x++) {
			System.out.println(getName() + ":" + x);
			Thread.yield();
		}
	}
}


  守護線程:
         public final void setDaemon(boolean on):將該線程標記爲守護線程或用戶線程。
         當正在運行的線程都是守護線程時,Java 虛擬機退出。 該方法必須在啓動線程前調用。 
         遊戲:坦克大戰。

public class ThreadDaemonDemo {
	public static void main(String[] args) {
		ThreadDaemon td1 = new ThreadDaemon();
		ThreadDaemon td2 = new ThreadDaemon();
 
		td1.setName("關羽");
		td2.setName("張飛");
 
		// 設置收穫線程
		td1.setDaemon(true);
		td2.setDaemon(true);
 
		td1.start();
		td2.start();
 
		Thread.currentThread().setName("劉備");
		for (int x = 0; x < 5; x++) {
			System.out.println(Thread.currentThread().getName() + ":" + x);
		}
	}
}
 
public class ThreadDaemon extends Thread {
	@Override
	public void run() {
		for (int x = 0; x < 100; x++) {
			System.out.println(getName() + ":" + x);
		}
	}
}


   線程中斷: 
          public final void stop():讓線程停止,過時了,但是還可以使用。
          public void interrupt():中斷線程。 把線程的狀態終止,並拋出一個InterruptedException。

public class ThreadStopDemo {
	public static void main(String[] args) {
		ThreadStop ts = new ThreadStop();
		ts.start();
 
		// 你超過三秒不醒過來,我就乾死你
		try {
			Thread.sleep(3000);
			// ts.stop();
			ts.interrupt();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
 
public class ThreadStop extends Thread {
	@Override
	public void run() {
		System.out.println("開始執行:" + new Date());
 
		// 我要休息10秒鐘,親,不要打擾我哦
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			// e.printStackTrace();
			System.out.println("線程被終止了");
		}
 
		System.out.println("結束執行:" + new Date());
	}
}

2,線程實現方式二

    a,步驟

  1.                      創建自定義類MyRunnable,實現Runnable接口;
  2.                      重寫run()方法
  3.                      創建MyRunnable對象
  4.                      創建Thread類對象,將MyRunnable對象作爲形參進行傳遞
  5.                      啓動線程

代碼:

public class RunnableDemo {
 
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//線程實現的第二種方法
		//創建線程對象
		MyRunnable mr1 = new MyRunnable();
		//創建Thread對象,將mr1作爲形參作爲傳遞
		/*
		Thread t1 = new Thread (mr1);
		Thread t2 = new Thread (mr1);
		t1.setName("線程一");
		t1.setName("線程二");
		*/
		Thread t1 = new Thread (mr1,"線程一");
		Thread t2 = new Thread (mr1,"線程二");
		t1.start();
		t2.start();
	}
 
}
class MyRunnable implements Runnable{
	public void run(){
		System.out.println(Thread.currentThread().getName()+":"+"yangjinbiao");
	}
}

三:線程安全

1,線程的生命週期

2,產生線程不安全的原因?

           :是否是多線程環境 ;是否有共享數據 ;是否有多條語句操作共享數據 。

3,解決線程安全:加鎖(synchronized )

            a,同步代碼塊

                       格式synchronized(對象){需要同步的代碼};

                   注意:可以是任意對象,但是必須使用的是同一個對象。

           b,同步方法

                         鎖對象爲;this

          c,靜態同步方法

                        鎖對象:類的字節碼文件對象。

           d:等待喚醒機制

                           Object類中提供了三個方法:

                                   wait():等待

                                   notify():喚醒單個線程

                                   notifyAll():喚醒所有線程

4,生產消費者模式(等待喚醒機制)

          共享的資源:

共同資源
public class Student {
	private String name;
	private int age;
	private boolean flag; // 默認情況是沒有數據,如果是true,說明有數據
 
	public synchronized void set(String name, int age) {
		// 如果有數據,就等待
		if (this.flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
 
		// 設置數據
		this.name = name;
		this.age = age;
 
		// 修改標記
		this.flag = true;
		this.notify();
	}
 
	public synchronized void get() {
		// 如果沒有數據,就等待
		if (!this.flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
 
		// 獲取數據
		System.out.println(this.name + "---" + this.age);
 
		// 修改標記
		this.flag = false;
		this.notify();
	}
}

生產者:

public class SetThread implements Runnable {
 
	private Student s;
	private int x = 0;
 
	public SetThread(Student s) {
		this.s = s;
	}
 
	@Override
	public void run() {
		while (true) {
			if (x % 2 == 0) {
				s.set("林青霞", 27);
			} else {
				s.set("劉意", 30);
			}
			x++;
		}
	}
}

消費者:


public class GetThread implements Runnable {
	private Student s;
 
	public GetThread(Student s) {
		this.s = s;
	}
 
	@Override
	public void run() {
		while (true) {
			s.get();
		}
	}

測試:


public class StudentDemo {
	public static void main(String[] args) {
		//創建資源
		Student s = new Student();
		
		//設置和獲取的類
		SetThread st = new SetThread(s);
		GetThread gt = new GetThread(s);
 
		//線程類
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(gt);
 
		//啓動線程
		t1.start();
		t2.start();
	}
}

四:線程池(第三種創建線程實現方式)

1,線程池的好處: 

             線程池的好處:線程池裏的每一個線程代碼結束後,並不會死亡,而是再次回到線程池中成爲空閒狀態,等待下一個對               象來使用。

2,創建線程池步驟:

          A:創建一個線程池對象,控制要創建幾個線程對象:public static ExecutorService newFixedThreadPool(int nThreads)
          B:這種線程池的線程可以執行:
             可以執行Runnable對象或者Callable對象代表的線程
              做一個類實現Runnable接口。
          C:調用如下方法即可
              Future<?> submit(Runnable task)
           <T> Future<T> submit(Callable<T> task)
       D:我就要結束,可以嗎?
          可以。

public class ExecutorsDemo {
	public static void main(String[] args) {
		// 創建一個線程池對象,控制要創建幾個線程對象。
		// public static ExecutorService newFixedThreadPool(int nThreads)
		ExecutorService pool = Executors.newFixedThreadPool(2);
 
		// 可以執行Runnable對象或者Callable對象代表的線程
		pool.submit(new MyRunnable());
		pool.submit(new MyRunnable());
 
		//結束線程池
		pool.shutdown();
	}
}
 
public class MyRunnable implements Runnable {
 
	@Override
	public void run() {
		for (int x = 0; x < 100; x++) {
			System.out.println(Thread.currentThread().getName() + ":" + x);
		}
	}
 
}

3,線程的第三種實現方案-實現Callable<Integer> 接口:(使用線程池實現)

public class CallableDemo {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		// 創建線程池對象
		ExecutorService pool = Executors.newFixedThreadPool(2);
 
		// 可以執行Runnable對象或者Callable對象代表的線程
		Future<Integer> f1 = pool.submit(new MyCallable(100));
		Future<Integer> f2 = pool.submit(new MyCallable(200));
 
		// V get()
		Integer i1 = f1.get();
		Integer i2 = f2.get();
 
		System.out.println(i1);
		System.out.println(i2);
 
		// 結束
		pool.shutdown();
	}
}

線程類:


public class MyCallable implements Callable<Integer> {
 
	private int number;
 
	public MyCallable(int number) {
		this.number = number;
	}
 
	@Override
	public Integer call() throws Exception {
		int sum = 0;
		for (int x = 1; x <= number; x++) {
			sum += x;
		}
		return sum;
	}

 

4,創建線程池的方式;

①. newFixedThreadPool(int nThreads)

創建一個固定長度的線程池,每當提交一個任務就創建一個線程,直到達到線程池的最大數量,這時線程規模將不再變化,當線程發生未預期的錯誤而結束時,線程池會補充一個新的線程。

②. newCachedThreadPool()

創建一個可緩存的線程池,如果線程池的規模超過了處理需求,將自動回收空閒線程,而當需求增加時,則可以自動添加新線程,線程池的規模不存在任何限制。

③. newSingleThreadExecutor()

這是一個單線程的Executor,它創建單個工作線程來執行任務,如果這個線程異常結束,會創建一個新的來替代它;它的特點是能確保依照任務在隊列中的順序來串行執行。

④. newScheduledThreadPool(int corePoolSize)

創建了一個固定長度的線程池,而且以延遲或定時的方式來執行任務,類似於Timer。

五:線程組

public class ThreadGroupDemo {
	public static void main(String[] args) {
		// method1();

		// 我們如何修改線程所在的組呢?
		// 創建一個線程組
		// 創建其他線程的時候,把其他線程的組指定爲我們自己新建線程組
		method2();

		// t1.start();
		// t2.start();
	}

	private static void method2() {
		// ThreadGroup(String name)
		ThreadGroup tg = new ThreadGroup("這是一個新的組");

		MyRunnable my = new MyRunnable();
		// Thread(ThreadGroup group, Runnable target, String name)
		Thread t1 = new Thread(tg, my, "林青霞");
		Thread t2 = new Thread(tg, my, "劉意");
		
		System.out.println(t1.getThreadGroup().getName());
		System.out.println(t2.getThreadGroup().getName());
		
		//通過組名稱設置後臺線程,表示該組的線程都是後臺線程
		tg.setDaemon(true);
	}

	private static void method1() {
		MyRunnable my = new MyRunnable();
		Thread t1 = new Thread(my, "林青霞");
		Thread t2 = new Thread(my, "劉意");
		// 我不知道他們屬於那個線程組,我想知道,怎麼辦
		// 線程類裏面的方法:public final ThreadGroup getThreadGroup()
		ThreadGroup tg1 = t1.getThreadGroup();
		ThreadGroup tg2 = t2.getThreadGroup();
		// 線程組裏面的方法:public final String getName()
		String name1 = tg1.getName();
		String name2 = tg2.getName();
		System.out.println(name1);
		System.out.println(name2);
		// 通過結果我們知道了:線程默認情況下屬於main線程組
		// 通過下面的測試,你應該能夠看到,默任情況下,所有的線程都屬於同一個組
		System.out.println(Thread.currentThread().getThreadGroup().getName());
	}
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章