------- android培訓、java培訓、期待與您交流! ----------
我們使用計算機時,計算機上有很多的程序在執行,每個程序都被稱之爲一個進程,但是進程在執行的過程中,往往我們會看到一個程序同時做着多件不同的事情,其實並不是這樣子的,這就是利用了多線程,每個事情就是一個線程,程序在執行過程中不斷的來回切換正在執行線程,只不過CPU的執行速度太快以至於我們認爲程序在同時做着不同的事情。現在我們就來看看如何使用java開發多線程。
java創建多線程有兩種方式。
java中提供了一類一接口兩種方式創建多線程,類是Thread類,接口是Runnable接口
方式一:通過查找API發現Thread類是一個抽象類,我們要創建抽象類的實例實際上需要的是抽象類的子類對象。
對象的問題解決了以後,我們又該如何啓動線程,我們要用多線程做的事情又該怎麼寫呢?
其實在Thread類中提供了兩個方法一個是run()方法,一個是start()方法,根據API中的介紹我們啓動線程調用的是start()方法,並且start()方法的底層其實也是調用run()方法。我們需要線程做得事情的代碼也是放在了run()方法中。
首先創建Thread類的子類MyThread類
其次重寫run()方法
最後在main方法中創建子類對象並開啓線程
package cn.itheima01;
public class MyThread extends Thread{
@Override
public void run() {
for(int x = 0; x < 100; x++){
System.out.println(this.getName()+"--"+x);
}
}
}
package cn.itheima01;
public class MyThreadDemo {
public static void main(String[] args) {
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
mt1.start();
mt2.start();
}
}
這樣一個簡單的多線程的例子就寫完了。
方式二:通過接口去實現多線程,java提供了Runnable接口,只需要提供Runnable接口的子類對象同樣可以完成上述的操作,下面我們就來看看怎麼做的。
package cn.itheima02;
public class MyRunnable implements Runnable{
@Override
public void run() {
for(int x = 0; x < 100; x++){
System.out.println(Thread.currentThread().getName()+","+x);
}
}
}
package cn.itheima02;
public class MyThreadDemo {
public static void main(String[] args) {
MyRunnable mr1 = new MyRunnable();
Thread th1 = new Thread(mr1);
Thread th2 = new Thread(mr1);
th1.start();
th2.start();
}
}
以上兩種方法,就是使用java實現多線程的方法,其實以上兩種放發我們發現了還有很大的缺陷,就是數據不能共享。
那麼java就提供了一個機制,同步機制。同步進制就是對線程加鎖,只有鎖對象是同一個時,程序纔會往下執行
下面我們來看看java是怎麼利用鎖機制來同步的。
java提供了關鍵字synchronized,
需求:賣票,假設現在有100張票,有兩個窗口同時進行售票,用程序實現
分析:兩個窗口同時進行售票的話,就代表了有兩個線程。數據是100
package cn.itheima10;
public class SellTicket implements Runnable {
private int tickets = 100;
private Object obj = new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "張電影票");
}
}
}
}
}
上面類中用到了一個sleep()方法,sleep()方法用於讓線程休眠,100所指的是100毫秒。package cn.itheima10;
public class ThreadTicketDemo {
public static void main(String[] args) {
SellTicket st = new SellTicket();
Thread t1 = new Thread(st,"售票窗口1");
Thread t2 = new Thread(st,"售票窗口2");
Thread t3 = new Thread(st,"售票窗口3");
t1.start();
t2.start();
t3.start();
}
}
其實上述方法使用的是同步代碼塊去實現,我們可以將同步代碼塊換成同步方法去實現,不過從上面的例子我們發現,用的是Object對象鎖,那麼同步方法的鎖又是什麼呢?
SellTicket類中的售票部分改成普通方法和靜態
package cn.itheima11;
public class SellTicket implements Runnable {
private static int tickets = 100;
private Object obj = new Object();
private int x = 0;
@Override
public void run() {
while (true) {
if(x%2==0){
synchronized (SellTicket.class) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "張電影票");
}
}
}else{
sell();
}
x++;
}
}
private synchronized void sell() {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "張電影票");
}
}
}
package cn.itheima11;
public class SellTicket implements Runnable {
private static int tickets = 100;
private Object obj = new Object();
private int x = 0;
@Override
public void run() {
while (true) {
if(x%2==0){
synchronized (SellTicket.class) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "張電影票");
}
}
}else{
sell();
}
x++;
}
}
private static synchronized void sell() {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "張電影票");
}
}
}
改成以上方法實現,效果一樣,但是同步方法和靜態同步方法的的鎖對象是什麼呢?
其實同步方法的鎖對象是this
而靜態同步方法的鎖對象是當前類對象的字節碼文件