多线程

来源:互联网 发布:淘宝好评评语 编辑:程序博客网 时间:2024/06/03 21:17

描述

问题描述:有4个线程和1个公共的字符数组。线程1的功能就是向数组输出A,线程2的功能就是向字符输出B,线程3的功能就是向数组输出C,线程4的功能就是向数组输出D。要求按顺序向数组赋值ABCDABCDABCD,ABCD的个数由线程函数1的参数指定。[注:C语言选手可使用WINDOWS SDK库函数]
接口说明:
void init();  //初始化函数
void Release(); //资源释放函数
unsignedint__stdcall ThreadFun1(PVOID pM)  ; //线程函数1,传入一个int类型的指针[取值范围:1 – 250,测试用例保证],用于初始化输出A次数,资源需要线程释放
unsignedint__stdcall ThreadFun2(PVOID pM)  ;//线程函数2,无参数传入
unsignedint__stdcall ThreadFun3(PVOID pM)  ;//线程函数3,无参数传入
Unsigned int __stdcall ThreadFunc4(PVOID pM);//线程函数4,无参数传入
char  g_write[1032]; //线程1,2,3,4按顺序向该数组赋值。不用考虑数组是否越界,测试用例保证

知识点字符串,循环,链表,队列,栈,查找,搜索,排序,树,图,数组,函数,指针,枚举,位运算,结构体,联合体,文件操作,递归运行时间限制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线程总结一下:

一、关于线程的一些概念:

首先,进程与线程是不同的,一般来说,一个程序有一个进程,而有多个线程。在单核CPU中,这些线程在宏观上讲是并行的,而在微观上来说每一时刻都只有一个线程在运行。在多核CPU中同一时刻会有多个线程运行,起数量取决于CPU数量。
其次,来说一下线程的生命周期:
线程的生命周期总的来说可以分为新建状态、就绪状态、运行状态、等待/阻塞状态和消亡状态(也有的书上会说有新建状态、就绪状态、运行状态、等待状态、休眠状态、阻塞状态和消亡状态),叫法会有不同,但实际所指的是一样的。
生命周期状态图:

二、线程的定义方式:

第一种:

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 0t1 0t2 1t1 1t2 2t1 2t2 3t1 3t2 4t1 4t2 5t2 6t1 5t1 6t1 7t1 8t2 7t1 9t1 10t1 11t1 12t2 8t2 9t1 13t2 10t1 14t1 15t1 16t1 17t1 18t1 19t2 11t2 12t2 13t2 14t2 15t2 16t2 17t2 18t2 19

可以看出,在t2线程运行到i==10的时候,调用了t1的join方法,从这时候开始就先执行t1,知道t1执行完毕才执行t2线程。

线程的中断:

以前可以使用stop()方法来中断线程,但是stop()方法是直接中断,线程来不及回收资源等行为,所以现在不建议使用stop()方法。现在中断可以使用标记变量来中断:
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线程运行完毕)。

线程的礼让:

线程礼让使用yield()方法,这也是一个静态方法,所以可以Thread.yield()直接使用,功能就是让当前线程进入就绪状态,CPU重新选择具有同样优先级的线程进入运行状态。yield()方法只是一种暗示,当前线程是否进入就绪状态还是由CPU决定。

线程的优先级

在线程调用start()方法之前可以设置线程优先级,使用setPriority()方法设置,参数为1-10(main线程的优先级是Thread.NORM_PRIORITY(5)),系统始终会选择就绪状态下优先级较高的进入运行状态,高优先级的运行几率比较大,低优先级的运行几率比较小。

线程同步

首先比较经典的是卖火车票:
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完成递减操作,所以就出现了负值。
此时需要对共享资源上锁,当一个线程进入run()方法时禁止其他线程进入run()方法,其他线程阻塞,当线程释放共享资源以后其他线程才能进入就绪状态,由CPU选择一个线程进入run()方法,并上锁,其它线程再进入阻塞状态。
修改以后为:
<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关键字也可以放在方法前面,比如说:
public synchronized void doit(){……}
其效果与上面的例子相同。


最后,以上的内容都是根据我的理解总结而来,如果有什么不对的地方欢迎大家指出,万分感谢!有什么需要讨论的可以在评论中留言,博主会尽快回复:)
0 0