描述 |
問題描述:有4個線程和1個公共的字符數組。線程1的功能就是向數組輸出A,線程2的功能就是向字符輸出B,線程3的功能就是向數組輸出C,線程4的功能就是向數組輸出D。要求按順序向數組賦值ABCDABCDABCD,ABCD的個數由線程函數1的參數指定。[注:C語言選手可使用WINDOWS SDK庫函數] |
---|---|
知識點 | 字符串,循環,鏈表,隊列,棧,查找,搜索,排序,樹,圖,數組,函數,指針,枚舉,位運算,結構體,聯合體,文件操作,遞歸 |
運行時間限制 | 10M |
內存限制 | 128 |
輸入 |
輸入一個int整數 |
輸出 |
輸出多個ABCD |
樣例輸入 | 10 |
樣例輸出 | ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD |
import java.util.Scanner;
import java.io.IOException;
public class Main
{
public static int N;
public static void main(String[] args) throws IOException
{
Scanner sca = new Scanner(System.in);
N = sca.nextInt();
sca.close();
final Test obj = new Test();
Thread tA = new Thread()
{
public void run()
{
obj.m1(N);
}
};
tA.start();
Thread tB = new Thread()
{
public void run()
{
obj.m2(N);
}
};
tB.start();
Thread tC = new Thread()
{
public void run()
{
obj.m3(N);
}
};
tC.start();
Thread tD = new Thread()
{
public void run()
{
obj.m4(N);
}
};
tD.start();
try {
tA.join();
tB.join();
tC.join();
tD.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(obj.ch);
}
}
class Test
{
static int count;
volatile int target = 1;
public static String ch = "";
synchronized void m1(int n)
{
for (int i = 0; i < n; i++)
{
while (target != 1)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
ch += "A";
target = 2;
notifyAll();
}
}
synchronized void m2(int n)
{
for (int i = 0; i < n; i++)
{
while (target != 2)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
ch += "B";
target = 3;
notifyAll();
}
}
synchronized void m3(int n)
{
for (int i = 0; i < n; i++)
{
while (target != 3)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
ch += "C";
target = 4;
notifyAll();
}
}
synchronized void m4(int n)
{
for (int i = 0; i < n; i++)
{
while (target != 4)
{
try
{
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
ch += "D";
target = 1;
notifyAll();
}
}
}
我承認這個不是很符合題意,但是大體上來說還是達到了題中所說的,提交正確以後,我看了一下別人的正確代碼,我失望了,都是直接輸出,除了main線程意外沒有其他線程,也就是騙了機器……
好了,下面就我所理解的java線程總結一下:
一、關於線程的一些概念:
二、線程的定義方式:
第一種:
public class Main extends Thread
{
public void run()
{
System.out.println("繼承Thread定義線程!");
}
public static void main(String[] args)
{
Main main = new Main();
main.start();
}
}
run()函數爲Thread的內部函數,重寫的run()函數的功能就是希望讓線程完成的任務。第二種:
public class Main implements Runnable
{
public void run()
{
System.out.println("實現接口Runnable定義線程!");
}
public static void main(String[] args)
{
Main test = new Main();
Thread t = new Thread(test);
t.start();
}
}
run()函數同上,這種方法比較靈活,首先可以在已經有繼承類的情況下使用線程,而且可以創建多個線程來完成任務。
注意,其實main也是一個線程,它的啓動的動作由JVM來控制,其他線程必須由自己來控制。
三、線程操作方法:
線程的休眠:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
sleep()方法的基本語法格式是:
public static void sleep(long millis) throws InterruptedException;
public static void sleep(long millis ,int nanos) throws InterruptedException;
millis表示線程睡眠的毫秒數,nanos表示線程睡眠的納秒數。同時注意sleep方法是靜態方法,其使用位置比較隨意,在線程內調用就是當前線程進入睡眠狀態。
線程的加入:
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
在一個線程中調用其他線程的join方法意味着先執行其他線程,而當前線程進入就緒狀態,在其他線程執行完畢後再執行當前線程。public class Main
{
public static void main(String[] args)
{
Thread t1 = new Thread(new Runnable(){
public void run()
{
for(int i = 0; i < 20; i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
},"t1");
Thread t2 = new Thread(new Runnable(){
public void run()
{
for(int i = 0; i < 20; i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
if(i == 10)
{
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
},"t2");
t1.start();
t2.start();
}
}
它的運行結果爲:t2 0
t1 0
t2 1
t1 1
t2 2
t1 2
t2 3
t1 3
t2 4
t1 4
t2 5
t2 6
t1 5
t1 6
t1 7
t1 8
t2 7
t1 9
t1 10
t1 11
t1 12
t2 8
t2 9
t1 13
t2 10
t1 14
t1 15
t1 16
t1 17
t1 18
t1 19
t2 11
t2 12
t2 13
t2 14
t2 15
t2 16
t2 17
t2 18
t2 19
可以看出,在t2線程運行到i==10的時候,調用了t1的join方法,從這時候開始就先執行t1,知道t1執行完畢才執行t2線程。
線程的中斷:
public class Main implements Runnable
{
private static boolean symbol = true;
public void run()
{
while(symbol)
{
System.out.println(0);
}
}
public static void main(String[] args)
{
Main test = new Main();
Thread t1 = new Thread(test);
t1.start();
symbol = false;
}
}
當需要中斷的時候直接賦值給symbol爲false,t1線程就會中斷(t1線程運行完畢)。線程的禮讓:
線程的優先級
線程同步
public class Main implements Runnable
{
int count = 10;//火車票數量
public void run()
{
while(true)
{
if(count > 0)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"賣出"+count--);
}
}
}
public static void main(String[] args)
{
Main test = new Main();
Thread t1 = new Thread(test,"窗口1");
Thread t2 = new Thread(test,"窗口2");
Thread t3 = new Thread(test,"窗口3");
t1.start();
t2.start();
t3.start();
}
}
運行結果是:窗口2賣出10
窗口1賣出9
窗口3賣出9
窗口1賣出8
窗口2賣出7
窗口3賣出6
窗口1賣出4
窗口2賣出5
窗口3賣出3
窗口2賣出2
窗口1賣出1
窗口3賣出0
窗口2賣出-1
可以看到最後兩行的票號爲0和負數,這是因爲count變成1的時候,三個線程都對其有存儲功能,當線程1執行run()方法時,還沒有來得及遞減count,就指定它調用sleep()方法進入就緒狀態,這時其他線程進入run()方法,發現count仍然大於0,而線程1休眠時間又到了,將count遞減,同時其他線程也對count完成遞減操作,所以就出現了負值。<pre name="code" class="java">public class Main implements Runnable
{
volatile int count = 10;//火車票數量
public void run()
{
while(true)
{
synchronized("")
{
if(count > 0)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"賣出"+count--);
}
}
}
}
public static void main(String[] args)
{
Main test = new Main();
Thread t1 = new Thread(test,"窗口1");
Thread t2 = new Thread(test,"窗口2");
Thread t3 = new Thread(test,"窗口3");
t1.start();
t2.start();
t3.start();
}
}
使用了synchronized關鍵字,執行結果是:窗口1賣出10
窗口1賣出9
窗口3賣出8
窗口3賣出7
窗口2賣出6
窗口2賣出5
窗口2賣出4
窗口2賣出3
窗口3賣出2
窗口1賣出1
synchronized關鍵字也可以放在方法前面,比如說: