我看到论坛上有个帖子,是介绍某次迅雷面试题目的,其中有一个题目是关于线程的,具体如下:
有三个线程,线程名称分别是A,B,C,要求编写代码实现输出这三个线程的名字 ABCABCABC……一共十次,当然,这三个线程要run起来,也就是说,要在程序中控制三个线程的顺序运行。小弟不才,写了如下一个代码:
package thread;public class threadrecyle {
public static void main(String[] args) {
mythread A = new mythread("A");
mythread B = new mythread("B");
mythread C = new mythread("C");
A.start();B.start();C.start();
}
}
class mythread extends Thread{
mythread(String s){
this.setName(s);
}
static int j = 0;
static boolean goa = true;
static boolean gob = false;
static boolean goc = false;
static boolean = true;
public void run(){
while( ){
if(this.getName().equals("A") && goa ){
System.out.print(this.getName());
gob = true;
goa = false;
}
if(this.getName().equals("B") && gob){
System.out.print(this.getName());
goc = true;
gob = false;
}
if(this.getName().equals("C") && goc ){
System.out.print(this.getName());
goa = true;
goc = false;
j++;
if(j==10){goa = false; = false;}
}
}
}
}
虽然可以实现,但是后来在网上逛的时候,发现这样一个问题,线程的目的不就是为了实现并发性么?实现了这个要求,那么跟并发不就违背了么?并发?顺序控制?这看上去时矛盾的啊!或者是我对线程理解的太肤浅么?望各位大侠给出宝贵观点和经验!!
有三个线程,线程名称分别是A,B,C,要求编写代码实现输出这三个线程的名字 ABCABCABC……一共十次,当然,这三个线程要run起来,也就是说,要在程序中控制三个线程的顺序运行。小弟不才,写了如下一个代码:
package thread;public class threadrecyle {
public static void main(String[] args) {
mythread A = new mythread("A");
mythread B = new mythread("B");
mythread C = new mythread("C");
A.start();B.start();C.start();
}
}
class mythread extends Thread{
mythread(String s){
this.setName(s);
}
static int j = 0;
static boolean goa = true;
static boolean gob = false;
static boolean goc = false;
static boolean = true;
public void run(){
while( ){
if(this.getName().equals("A") && goa ){
System.out.print(this.getName());
gob = true;
goa = false;
}
if(this.getName().equals("B") && gob){
System.out.print(this.getName());
goc = true;
gob = false;
}
if(this.getName().equals("C") && goc ){
System.out.print(this.getName());
goa = true;
goc = false;
j++;
if(j==10){goa = false; = false;}
}
}
}
}
虽然可以实现,但是后来在网上逛的时候,发现这样一个问题,线程的目的不就是为了实现并发性么?实现了这个要求,那么跟并发不就违背了么?并发?顺序控制?这看上去时矛盾的啊!或者是我对线程理解的太肤浅么?望各位大侠给出宝贵观点和经验!!
但是,考题并非全是要解决实际问题的。
楼主的这道题,其实是想调查程序员,是否有实现线程间相互协作的能力。引入了多线程技术,虽然一定程度上解决了CPU密集型的任务,
但是,也引入了线程安全、线程协作等一些问题,
实际应用中,我们可能只专注于某个问题的技术实现方案。
但,考题,则会侧重某个点来考察你,而非解决实际问题。
可以把一个文件的下载过程,分为三个部分:
网络数据传输,内存缓冲区数据管理,本地硬盘数据管理。
那么,其中内存数据管理,很可能就是一个CPU密集型的案例
(多个数据源公用一个数据缓冲区,并且数据并非都是连贯的,
这就要求缓冲区管理程序要不停的根据数据源的数据变动,
以及硬盘数据的写入变动,来调整、管理缓冲区,提高整体效率)当然,我这只是一个假设,如果假设成立,那么,
整个下载程序,
网络数据传输部分,只要一个线程来维护多个连接就OK了
(因为这个工作相对不消耗CPU而多消耗网络通信);
本地硬盘数据管理部分,只要一两个线程负责多个文件的写入工作就OK了
(这个工作也是大部分都是硬盘的IO操作,相对不消耗CPU);
内存数据缓冲区管理部分,相对上述两个部分,以及整体来讲,CPU的消耗要大得多,
可以考虑多个线程来完成
(两边的情况都在变动,中间的缓冲区也在变动,所以,需要CPU根据不同的情况,
及时调整、管理这些数据,使得整体效率提高)。
private static ReentrantLock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
/** int state:0:c运行完,1:A运行完,2:B运行完 */
private static int state = 0; public final static int A = 0;
public final static int B = 1;
public final static int C = 2;
/**
* @Description:
* @param args
* @Others:
*/
public static void main(String[] args) { Mythread threadA = new Mythread(A);
Mythread threadB = new Mythread(B);
Mythread threadC = new Mythread(C);
threadA.start();
threadB.start();
threadC.start();
} public static class Mythread extends Thread {
private int name;
Mythread(int name) {
this.name = name;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
while (name != state) {
condition.await();
}
switch (name) {
case A: {
System.out.print("A");
break;
}
case B: {
System.out.print("B");
break;
}
case C: {
System.out.print("C");
break;
}
}
// 条件满足,执行
state = (state+1)%3;
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}}
boolean a=true,b=false,c=false;
public void run(){
while(!Thiread.interrupted()){
if(a){
a=false;
b=true;
//do a
}
if(b){
b=false;
c=true;
//do b
}
if(c){
v=false;
a=true;
//do c
}
}
}这个应该也行吧
if(a){
a=false;
b=true;
//do a
}
打印的是AAA
顺便说一声,LZ的代码有问题,LZ再好好想想。
System.out.print(this.getName());
gob = true;
try {sleep(10);} catch (Exception e) {} //LZ可试着用sleep来模拟CPU分配时间,看看是什么结果
goa = false;
}LZ的程序严格依赖各个标志,一旦标志变换顺序被打乱,程序就崩了
线程的执行是由系统随机调度的,也就是当线程A执行完gob=true时,很有可能CPU被系统收回,此时B执行,C执行,当C执行到goa=true时,假设系统把C的CPU收回,分配给A,而A得到CPU权限后继续下一条代码goa=false;此时标志位乱了,程序无法继续正常执行。
LZ对线程不熟悉,想的不周到,这不怪你,LZ慢慢体会吧,这只是举例一种可能,因为线程是随机的,所有还有很多可能
public class test {
public static void main(String[] args) {
pr p = new pr();
Thread a = new Thread(p);
a.setName("A");
a.start();
Thread b = new Thread(p);
b.setName("B");
b.start();
Thread c = new Thread(p);
c.setName("C");
c.start();
}
}
class pr implements Runnable {
private static int num = 0;
private static boolean a=true;
private static boolean b=false;
private static boolean c=false;
public synchronized void run() {
long start = System.currentTimeMillis();
while(true) {
if(Thread.currentThread().getName().equals("A")) {
if(a) {
System.out.print(Thread.currentThread().getName());
a=false;
b=true;
num++;
}
else {
try {
this.notifyAll();
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if(Thread.currentThread().getName().equals("B")) {
if(b) {
b=false;
c=true;
System.out.print(Thread.currentThread().getName());
num++;
}
else {
try {
this.notifyAll();
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if(Thread.currentThread().getName().equals("C")) {
if(c) {
c=false;
a=true;
System.out.print(Thread.currentThread().getName());
num++;
}
else {
try {
this.notifyAll();
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
if(num==3000) {
System.out.println();
System.out.print(System.currentTimeMillis()-start);
System.exit(0);
}
}
}
}
csdn第一帖... 嘿嘿,试试能不能正常发代码
2: this.notifyAll(); this.wait();这种写法虽然我推敲了一下没有什么问题,但总觉得怪怪的,我工作几年来好像没有见过这种写法,呵呵。不过总的来说还是挺好的。
我纯粹是新手,刚看视频自学的。不过阿宝可能说的是同步问题里的东西吧,比如
gob = true;
goa = false
这两句应该加个synchronized.....
线程是间歇性工作的
不知道说的对不
也不应该说 自己对线程特别拿手的吧。
大家只是讨论学习。。 在说了 说的对只是针对 楼主这一种类型的。。
学习才是主要的。
//LZ可试着用sleep来模拟CPU分配时间,看看是什么结果
线程的控制是随机的,不是因为你一时的结果正确就表示正确
你自己说的话有没有错,你自己再好好思考吧。
年轻人不要浮躁,我在15L的回复如果不是你没好好看,就是你还没完全理解。
15L已经把Lz的程序漏洞分析清楚了。
能一眼就看出了Lz的程序有问题,这不是装能装出来的,有本事你也装一个试试。
不要被人指出错误就进行人身攻击,不懂就要谦虚地去学。
[threadA]
gob = true;
[threadB]
goc = true;
gob = false;
[threadB]
goa = true;
goc = false;
[threadA]
goa = false;
这种情况下会出现三个变量全为false,导致三个线程全不能进入条件。这种情况打印顺序不会发生变化,但是后面不再会打印了。
--说哪里错了就Ok,不要装深沉。
年轻人不要浮躁,我在15L的回复如果不是你没好好看,就是你还没完全理解。
15L已经把Lz的程序漏洞分析清楚了。
能一眼就看出了Lz的程序有问题,这不是装能装出来的,有本事你也装一个试试。
--我没你会装,不过我在#12楼已经给出了正确的代码。
12L的代码没看,你不装,是因为你根本没看出LZ的问题,你写出代码,无非是想炫耀一下,好让别人评论一番,结果被人忽略后心有不甘。
你想要代码,我给你一段,最原始的线程协作
class Job {
int count = 0;
public static void main(String[] args) {
new Job().start();
}
public void start() {
new JobThread("A", 0).start();
new JobThread("B", 1).start();
new JobThread("C", 2).start();
}
synchronized void doJob(int id) {
if (count%3 == id) {
System.out.print(Thread.currentThread().getName());
count++;
notifyAll();
} else {
try {
wait();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
private class JobThread extends Thread {
int id;
public JobThread(String name, int id) {
super(name);
this.id = id;
}
public void run() {
while (Job.this.count < 30) {
Job.this.doJob(id);
yield();
}
}
}
}
gob = true;
goa = false
这个两个要当做一个原子操作才能保持条件的一致性我又不是不知道,我知道这样会存在问题,但没有仔细去推敲会引起什么问题,所以也就没有在这个问题上下论断,只是说楼主代码能得到正确结果,你说我说的存在什么问题?(不是问你楼主的代码存在什么问题,我从没有说过楼主的代码不存在问题)
你如果真对线程了解,又岂会看不出问题?连LS的年轻人,指点后都能看出来了。
你的话本来就不严谨,再见上自己又说认真看了一下,于是下了个结论,应该也是能够得到正确的结果,而且,你还是对我的回帖做的回复,也就是说我在帖子里的都把问题说出来了,你还没看出来,还得出这样的结论,说到这里就不用解释了,你懂的,如此认真还找不出问题?不要以为自己写了个程序就表示自己很牛,不知就是不知。你这属于典型的钻牛角尖,明白的人都知道你的解释很苍白,没看出问题来就是没看出问题来,不用作无谓的解释,你自己也说没仔细推敲会引起问题,既知有问题,又岂能草率下结论?而且对你所谓的能得到正确的结果,我也说过一时的结果正确不代表正确,如果非要说别人挑刺,那我就挑出你的语句问题,应该有时能得到正确的结果,这句话和你那句话,意思可谓差远了。有错不可怕,可怕的是错了还不承认,甚至还进行人身攻击。写程序容易,难的是发现别人程序的漏洞,要不然所谓的黑客就跟你一样满天飞了。
你如果真对线程了解,又岂会看不出问题?连LS的年轻人,指点后都能看出来了。
你的话本来就不严谨,再见上自己又说认真看了一下,于是下了个结论,应该也是能够得到正确的结果,而且,你还是对我的回帖做的回复,也就是说我在帖子里的都把问题说出来了,你还没看出来,还得出这样的结论,说到这里就不用解释了,你懂的,如此认真还找不出问题?不要以为自己写了个程序就表示自己很牛,不知就是不知。你这属于典型的钻牛角尖,明白的人都知道你的解释很苍白,没看出问题来就是没看出问题来,不用作无谓的解释,你自己也说没仔细推敲会引起问题,既知有问题,又岂能草率下结论?而且对你所谓的能得到正确的结果,我也说过一时的结果正确不代表正确,如果非要说别人挑刺,那我就挑出你的语句问题,应该有时能得到正确的结果,这句话和你那句话,意思可谓差远了。有错不可怕,可怕的是错了还不承认,甚至还进行人身攻击。写程序容易,难的是发现别人程序的漏洞,要不然所谓的黑客就跟你一样满天飞了。厉害,我多线程没怎么入门,要学的东西还有很多啊。