java多线程--几个多线程面试题小结
面试题1:编写程序实现,子线程循环10次,接着主线程循环20次,接着再子线程循环10次,主线程循环20次,如此反复,循环50次.
package com.wang.reflect; //编写功能类,实现子线程和主线程的功能 class Function{ private boolean flag=false; //子线程要实现的功能 public synchronized void sub(){ while(flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for(int i=0;i<10;i++){ //for循环内定义子线程的功能,这里简单的假设为打印一句话,主线程同理 System.out.println("sub"+i); } flag=true; this.notify(); } //主线程要实现的功能 public synchronized void main(){ while(!flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for(int i=0;i<20;i++){ System.out.println("main"+i); } flag=false; this.notify(); } } public class Demo01 { public static void main(String[] args) { final Function f=new Function(); new Thread( new Runnable(){ @Override public void run() { for(int i=0;i<50;i++){ f.sub(); } } } ).start(); for(int i=0;i<50;i++){ f.main(); } } }
JDK1.5以后,出现了Lock和condition,Lock类似于synchronized功能,用来进行线程同步,Condition功能类似于Object类中的wait和notify方法,用于线程间的通信.上面的代码可以用Lock和Condition来改进,如下:
package com.wang.reflect; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; //编写功能类,实现子线程和主线程的功能 class Function{ private boolean flag=false; Lock lock=new ReentrantLock(); Condition con=lock.newCondition(); //子线程要实现的功能 public void sub(){ lock.lock(); try { while(flag){ try { con.await(); } catch (InterruptedException e) { e.printStackTrace(); } } for(int i=0;i<10;i++){ //for循环内定义子线程的功能,这里简单的假设为打印一句话,主线程同理 System.out.println("sub"+i); } flag=true; con.signal(); } finally{ lock.unlock(); } } //主线程要实现的功能 public synchronized void main(){ lock.lock(); try { while (!flag) { try { con.await(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < 20; i++) { System.out.println("main" + i); } flag = false; con.signal(); } finally{ lock.unlock(); } } } public class Demo01 { public static void main(String[] args) { final Function f=new Function(); new Thread( new Runnable(){ @Override public void run() { for(int i=0;i<50;i++){ f.sub(); } } } ).start(); for(int i=0;i<50;i++){ f.main(); } } }
面试题2:设计四个线程,其中两个线程每次对变量i加1,另外两个线程每次对i减1.
package com.wang.reflect; /** * 设计四个线程,其中两个线程每次对变量i加1,另外两个线程每次对i减1. * @author Administrator * */ public class Demo02 { private int i=0; public static void main(String[] args) { Demo02 demo=new Demo02(); Add add = demo.new Add(); Sub sub = demo.new Sub(); for(int i=1;i<=2;i++){ new Thread(add,"线程"+i).start(); new Thread(sub,"线程"+i).start(); } } //定义一个内部类Add,实现功能每次对i加一 class Add implements Runnable{ @Override public void run() { for(int i=0;i<10;i++){ addOne(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } //定义一个内部类Sub,实现功能每次对i减1 class Sub implements Runnable{ @Override public void run() { for(int i=0;i<10;i++){ subOne(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } public synchronized void addOne() { i++; System.out.println(Thread.currentThread().getName()+"加一的值为:"+i); } public synchronized void subOne(){ i--; System.out.println(Thread.currentThread().getName()+"减一的值为:"+i); } }
面试题3:自己编写代码,实现生产者-消费者模型功能.内容自由发挥,只需要表达思想.
代码中,自定义一个学生类,有name和age属性,属于共享对象,生产者负责为studnet对象赋值,消费者负责打印出student对象的name和age的值,当生产者赋值完以后通知消费者来打印,消费者打印完以后,通知生产者重新设置.
package com.wang.reflect; //学生实体类作为共享资源 class Student { private String name;// 姓名 private int age;// 年龄 boolean flag;// 标记变量,判断当前学生对象是否已创建赋值好 //生产者的功能 ,为studnet对象赋值 public synchronized void set(String name, int age) { if (this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.name = name; this.age = age; this.flag = true; this.notify(); } //消费者的功能,打印sutdent对象的内容 public synchronized void get() { if (!this.flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(name + ":::" + age); this.flag = false; this.notify(); } } // 模拟生产者线程类 class SetStudent implements Runnable { // 共享资源s private Student s; private int x = 0; public SetStudent(Student s) { this.s = s; } @Override public void run() { while (true) { if (x % 2 == 0) { s.set("郭靖", 27); } else { s.set("黄蓉", 18); } x++; } } } // 模拟消费者线程类 class GetStudent implements Runnable { // 共享资源s private Student s; public GetStudent(Student s) { this.s = s; } @Override public void run() { while (true) { s.get(); } } } // 测试类 public class Demo03{ public static void main(String[] args) { Student s = new Student(); SetStudent ss = new SetStudent(s); GetStudent gs = new GetStudent(s); Thread t1 = new Thread(ss, "生产者"); Thread t2 = new Thread(gs, "消费者"); t1.start(); t2.start(); } }
面试题4: 现有的程序代码模拟产生了16个日志对象,并且需要运行16秒才能打印完这些日志,请在程序中增加4个线程去调用parseLog()方法来分头打印这16个日志对象,程序只需要运行4秒即可打印完这些日志对象。
原始代码如下:
public class Test { public static void main(String[] args){ System.out.println("begin:"+(System.currentTimeMillis()/1000)); /*模拟处理16行日志,下面的代码产生了16个日志对象,当前代码需要运行16秒才能打印完这些日志。 修改程序代码,开四个线程让这16个对象在4秒钟打完。 */ for(int i=0;i<16;i++){ //这行代码不能改动 final String log = ""+(i+1);//这行代码不能改动 { Test.parseLog(log); } } } //parseLog方法内部的代码不能改动 public static void parseLog(String log){ System.out.println(log+":"+(System.currentTimeMillis()/1000)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
改写代码如下:
package com.wang.reflect; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public class Demo03 { public static void main(String[] args){ //定义一个线程共享的队列容器,可以使得数据由队列的一端输入,从另外一端输出 final BlockingQueue<String> queue=new ArrayBlockingQueue<String>(16); for(int i=0;i<4;i++){ new Thread(new Runnable(){ @Override public void run() { while(true){ try { parseLog(queue.take()); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } System.out.println("begin:"+(System.currentTimeMillis()/1000)); /*模拟处理16行日志,下面的代码产生了16个日志对象,当前代码需要运行16秒才能打印完这些日志。 修改程序代码,开四个线程让这16个对象在4秒钟打完。 */ for(int i=0;i<16;i++){ //这行代码不能改动 final String log = ""+(i+1);//这行代码不能改动 { try { queue.put(log); } catch (InterruptedException e) { e.printStackTrace(); } } } } //parseLog方法内部的代码不能改动 public static void parseLog(String log){ System.out.println(log+":"+(System.currentTimeMillis()/1000)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }