Java多線程(一)實作多線程
在Java中,可以用Thread、Runnable以及Callable實作多線程
Thread 實作多線程
用Thread方法那麼就是目标類繼承(extends)Thread類,然後重寫父類的run函數,在執行多線程程式時,使用start函數執行。
class sellTicket extends Thread{
private int tickets = 20;
@Override
public void run() {
try {
this.sell();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void sell() throws InterruptedException {
while(tickets>0)
{
System.out.println("賣了一張票,現在還有"+--this.tickets);
Thread.sleep(100);
}
}
}
public class testThread {
public static void main(String[] args) throws InterruptedException {
sellTicket st = new sellTicket();
st.start();
int index = 0;
while(true) {
System.out.println("--------------");
Thread.sleep(100);
if(index++>30)
break;
}
}
}
如果不使用多線程,那麼看main函數的話,肯定是先賣票(輸出賣票資訊),再輸出----------,但是使用了多線程以後,就是主線程main函數以及sellTicket 線程一起運作,得到了如下的結果。
Runnable 實作多線程
用Runnale實作多線程的方法與Thread是類似的,不同的是這個是implements Runnale,在執行多線程時是new一個Thread對象,并将Runnale的對象放入Thread對象中,再進行start()。
class sellTicket implements Runnable{
private int tickets = 20;
@Override
public void run() {
try {
this.sell();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void sell() throws InterruptedException {
while(tickets>0)
{
System.out.println("賣了一張票,現在還有"+--this.tickets);
Thread.sleep(100);
}
}
}
public class testThread {
public static void main(String[] args) throws InterruptedException {
sellTicket st = new sellTicket();
new Thread(st).start();
int index = 0;
while(true) {
System.out.println("--------------");
Thread.sleep(100);
if(index++>30)
break;
}
}
}
結果與上一個方法相同
Callable實作多線程
Callable實作多線程和上面兩種的差別在于Callable多線程操作後可以有傳回值,其次,用Callable實作的類的多線程操作寫在call()函數中,具體可以看下面代碼:
class TestCall implements Callable<String>
{
@Override
public String call() throws Exception {
for (int i=0;i<10;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
return Thread.currentThread().getName() + "完成線程操作";
}
}
public class testThread {
public static void main(String[] args) throws InterruptedException, ExecutionException {
TestCall t1 = new TestCall();
TestCall t2 = new TestCall();
TestCall t3 = new TestCall();
//建立執行服務
ExecutorService service = Executors.newFixedThreadPool(3);
//送出執行
Future<String> r1 = service.submit(t1);
Future<String> r2 = service.submit(t2);
Future<String> r3 = service.submit(t3);
//擷取結果
String rs1 = r1.get();
System.out.println(rs1);
String rs2 = r2.get();
System.out.println(rs2);
String rs3 = r3.get();
System.out.println(rs3);
//關閉服務
service.shutdownNow();
}
}
結果如下圖所示
Thread 與 Runnable 的差別和聯系
- Runnable的實作方式是實作其接口
- Thread的實作方式是繼承其類
- Thread實作了Runnable接口并進行了擴充,而Thread和Runnable的實質是實作的關系,不是同類東西,是以Runnable或Thread本身沒有可比性。
初學者會有這樣一個錯覺:Runnable更容易可以實作多個線程間的資源共享,而Thread卻不行,但實際上卻不是這樣的。
這是一段由Runnable方式寫成的多線程代碼
class sellTicket implements Runnable{
static int tickets = 20;
static Object o = new Object();
@Override
public void run() {
try {
this.sell();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void sell() throws InterruptedException {
while (tickets > 0) {
synchronized (o) {
if(tickets<=0)
break;
System.out.println(Thread.currentThread().getName() + "賣了一張票,現在還有" + --this.tickets);
Thread.sleep(100);
}
}
}
}
public class testThread {
public static void main(String[] args) throws InterruptedException, ExecutionException {
sellTicket st1 = new sellTicket();
sellTicket st2 = new sellTicket();
sellTicket st3 = new sellTicket();
new Thread(st1,"1").start();
new Thread(st2,"2").start();
new Thread(st3,"3").start();
}
}
然後将上段代碼改成Thread方式的如下
public class testThread {
public static void main(String[] args) throws InterruptedException, ExecutionException {
sellTicket st1 = new sellTicket();
sellTicket st2 = new sellTicket();
sellTicket st3 = new sellTicket();
st1.start();
st2.start();
st3.start();
}
}
class sellTicket extends Thread{
static int tickets = 20;
static Object o = new Object();
@Override
public void run() {
try {
this.sell();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void sell() throws InterruptedException {
while (tickets > 0) {
synchronized (o) {
if(tickets<=0)
break;
System.out.println(Thread.currentThread().getName() + "賣了一張票,現在還有" + --this.tickets);
Thread.sleep(100);
}
}
}
}
由此看無論哪種方式都可以實作多個線程之間的資源共享,隻需要做好同步或者鎖的操作即可。