一:Java中三種多線程的實現方式
在Java中實現多線程有兩種途徑,
- 繼承Thread類,重寫run方法,多線程啓動的方法,就是start方法。(單繼承的侷限)
public class TestThread extends Thread {
private String name;
public TestThread(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println(this.name + "-->" + i);
}
}
public static void main(String[] args) {
TestThread thread1 = new TestThread("線程1");
TestThread thread2 = new TestThread("線程2");
TestThread thread3 = new TestThread("線程3");
thread1.start();
thread2.start();
thread3.start();
}
}
- 實現Runnable接口,並且重寫run方法。多線程的啓動還是Thread的start方法。
public class TestRunnable implements Runnable {
private String name;
public TestRunnable(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 0; i < 200; i++) {
System.out.println(this.name + "-->" + i);
}
}
public static void main(String[] args) {
TestRunnable thread1 = new TestRunnable("線程1");
TestRunnable thread2 = new TestRunnable("線程2");
TestRunnable thread3 = new TestRunnable("線程3");
new Thread(thread1).start();
new Thread(thread2).start();
new Thread(thread3).start();
}
}
兩種方式的區別:
- 實現Runnable接口解決了單繼承的侷限,Thread類實現了Runable接口
- 線程資源共享,Runnable更好的詮釋了數據共享,多線程訪問同一資源
public static void main(String[] args) {
TestRunnable thread1 = new TestRunnable("線程1");
new Thread(thread1).start();
new Thread(thread1).start();
new Thread(thread1).start();
}
jdk1.5的新特性,線程執行完接收返回值,也是線程實現的第三種方式,
package com.java.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class TestCallable implements Callable<String> {
private int ticket = 10;
@Override
public String call() throws Exception {
for (int i = 0; i < 100; i++) {
if (ticket > 0) {
System.out.println("賣票,票數=" + ticket--);
}
}
return "票賣完了";
}
public static void main(String[] args) throws Exception {
TestCallable testCallable1 = new TestCallable();
TestCallable testCallable2 = new TestCallable();
FutureTask<String> futureTask1 = new FutureTask<>(testCallable1);
FutureTask<String> futureTask2 = new FutureTask<>(testCallable2);
new Thread(futureTask1).start();
new Thread(futureTask2).start();
System.out.println("futureTask1 = " + futureTask1.get());
System.out.println("futureTask2 = " + futureTask2.get());
}
}
二:線程的命名與取得,Thread.currentThread().getName(),線程能夠自動命名
Thread(Runnable target, String name)
Allocates a new
Thread
object.setName(String name)
Changes the name of this thread to be equal to the argument
name
.-
getName()
Returns this thread's name
public class TestRunnable implements Runnable {
private String name;
public TestRunnable(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
TestRunnable thread1 = new TestRunnable("線程1");
new Thread(thread1,"線程1").start();
new Thread(thread1).start();
new Thread(thread1,"線程3").start();
}
}
每一個JVM啓動,至少啓動兩個線程
- main線程,以及程序的子線程
- gc線程,負責垃圾回收
三:線程的休眠
- Thread.sleep(1000); 有先後差別
四:線程的優先級Thread類裏面提供的兩個方法,以及三個常量
setPriority(int newPriority)
Changes the priority of this thread.
-
Returns this thread's priority.
-
MIN_PRIORITY
The minimum priority that a thread can have.
-
The maximum priority that a thread can have.
-
The default priority that is assigned to a thread.
public static void main(String[] args) {
TestThread thread1 = new TestThread("線程1");
TestThread thread2 = new TestThread("線程2");
TestThread thread3 = new TestThread("線程3");
thread1.setPriority(MAX_PRIORITY);
thread2.setPriority(MIN_PRIORITY);
thread3.setPriority(NORM_PRIORITY);
thread1.start();
thread2.start();
thread3.start();
}
五:總結
- 主線程屬於中等優先級,
- Thread.currentThread()可以獲取當前線程的對象。
六:同步問題
多個線程訪問同一個資源需要考慮的問題,4個人賣5張票,在判斷和修改是分開執行的,最後一張票出現了資源的延遲,
如何解決同步的問題
當有線程在執行的時候,其他的線程先等待。在Java中要想實現線程的同步需要使用synchronized關鍵字。
使用方式,
- 同步代碼塊
- 同步方法
Java中有四種代碼塊,普通代碼塊,構造塊,靜態塊,同步塊。
- 以下是同步代碼塊,
- 以下是同步方法,
public class TestSynchronized implements Runnable {
private int ticket = 50;
@Override
public void run() {
try {
for (int i = 0; i < 200; i++) {
//賣票的過程
if (sell()) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized boolean sell() throws InterruptedException {
if (ticket > 0) {
// Thread.sleep(200);
System.out.println(Thread.currentThread().getName() + "...票數=" + this.ticket--);
return false;
} else {
return true;
}
}
public static void main(String[] args) {
TestSynchronized thread0 = new TestSynchronized();
new Thread(thread0,"票販子A").start();
new Thread(thread0,"票販子B").start();
new Thread(thread0,"票販子C").start();
new Thread(thread0,"票販子D").start();
}
}
死鎖:是一個線程對象等待另一個線程對象執行完畢後的操作結果,同步過多可能發生死鎖。
多個線程訪問一個資源需要考慮哪些問題,
- 同步問題,可以使用同步代碼塊,也可以使用同步方法
- 過多的使用同步可能造成死鎖
七:生產者和消費者
- 生產者負責生產數據,消費者負責取走數據
- 生產者每生產一組數據,消費者就取走一組數據
等待與喚醒,
- super.wait();
- super.notify();
sleep和wait得區別,
- sleep是Thread類的方法,wait是Object類的方法
- sleep可以設置休眠時間,時間一到自動喚醒,而wait需要notify去喚醒。