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();
}
}
}