java多线程--练习题总结

目录

 

练题1:编写程序实现,子线程循环3次,接着主线程循环5次,接着再子线程循环3次,主线程循环5次,如此反复,循环3次.

练习题2:设计四个线程,其中两个线程每次对变量i加1,另外两个线程每次对i减1.

练习题3:自己编写代码,实现生产者-消费者模型功能.内容自由发挥,只需要表达思想.

练习题4:现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?


练题1:编写程序实现,子线程循环3次,接着主线程循环5次,接着再子线程循环3次,主线程循环5次,如此反复,循环3次.

第一种实现方式:使用synchronized关键字

package com.lianxi;

public class ThreadMain2 {
 
	public static void main(String[] args) { 
		final ThreadFunction2 f2 = new ThreadFunction2();
		
		// 子线程循环3次
		new Thread(new Runnable(){
			public void run(){
				for(int i=0;i<3;i++){
					f2.subFunction();
				}
			}
		}).start();
		
		// 主线程循环3次
		for(int i=0;i<3;i++){
			f2.mainFunction();
		} 
	}

}
package com.lianxi;

// 编写功能类,实现子线程和主线程的功能
public class ThreadFunction2 {
	
	private boolean flag = false;
	
	// 主线程要实现的功能
	public synchronized void mainFunction(){
		while(!flag){
			try {
				this.wait();
			} catch (InterruptedException e) { 
				e.printStackTrace();
			}
		}
		for(int i=0;i<5;i++){
			System.out.println("mainFunction"+i);
		} 
		this.notify();
		flag = false;
	}
	
	// 子线程要实现的功能
	public synchronized void subFunction(){
		while(flag){
			try {
				this.wait();
			} catch (InterruptedException e) { 
				e.printStackTrace();
			} 
		}
		for(int i=0;i<3;i++){
			System.out.println("subFunction"+i);
		} 
		this.notify();
		flag = true;
	}

}

输出结果:

subFunction0
subFunction1
subFunction2
mainFunction0
mainFunction1
mainFunction2
mainFunction3
mainFunction4
subFunction0
subFunction1
subFunction2
mainFunction0
mainFunction1
mainFunction2
mainFunction3
mainFunction4
subFunction0
subFunction1
subFunction2
mainFunction0
mainFunction1
mainFunction2
mainFunction3
mainFunction4

第二种实现方式:使用 lock 锁和 Condition 接口

package com.lianxi;

public class ThreadMain {
 
	public static void main(String[] args) { 
		final ThreadFunction f = new ThreadFunction();
		
		// 子线程循环3次
		new Thread(new Runnable(){
			public void run(){
		        for(int i=0;i<3;i++){
		        	f.subFunction();
		        }
			}
		}).start();
		
		// 主线程循环3次
		for(int i=0;i<3;i++){
        	f.mainFunction();
        }

	}

}
package com.lianxi;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

// 编写功能类,实现子线程和主线程的功能
public class ThreadFunction extends Thread{
	
	private boolean flag = false;
	Lock lock = new ReentrantLock();
	Condition con = lock.newCondition();
	
    // 主线程要实现的功能
	public void mainFunction(){ 
		System.out.println("1.主线程开始"+" -- flag="+flag);
		lock.lock();
		try{ 
			while(!flag){ 
				try {
					System.out.println("2.主线程等待"+" -- flag="+flag);
					con.await();   // 使当前线程加入 await() 等待队列中,并释放当锁,当其他线程调用signal()会重新请求锁。与Object.wait()类似。
				} catch (InterruptedException e) { 
					e.printStackTrace();
				} 
			}  
			System.out.println("7.主线程开始循环5次"+" -- flag="+flag);
			for(int i=0;i<5;i++){ 
				System.out.println("mainFunction"+i+" -- flag="+flag); 
			}
			flag = false;
			System.out.println("8.唤醒子线程"+" -- flag="+flag);
			con.signal();  // 唤醒一个在 await()等待队列中的线程。与Object.notify()相似
		}finally{
			lock.unlock(); 
		}
		 
		
		
	}
	
    // 子线程要实现的功能
	public void subFunction(){ 
		System.out.println("3.子线程开始"+" -- flag="+flag);
		lock.lock(); 
		try{
			while(flag){
				try {
					System.out.println("6.子线程等待"+" -- flag="+flag);
					con.await();  // 使当前线程加入 await() 等待队列中,并释放当锁,当其他线程调用signal()会重新请求锁。与Object.wait()类似。
				} catch (InterruptedException e) { 
					e.printStackTrace();
				}  
			}
			System.out.println("4.子线程开始循环3次"+" -- flag="+flag);
			for(int i=0;i<3;i++){
				System.out.println("subFunction"+i+" -- flag="+flag);
			}
			flag = true;
			System.out.println("5.唤醒主线程"+" -- flag="+flag);
			con.signal(); // 唤醒一个在 await()等待队列中的线程。与Object.notify()相似
		}finally{
			lock.unlock();  
		}  
	} 
}

输出结果:

1.主线程开始 -- flag=false
2.主线程等待 -- flag=false
3.子线程开始 -- flag=false
4.子线程开始循环3次 -- flag=false
subFunction0 -- flag=false
subFunction1 -- flag=false
subFunction2 -- flag=false
5.唤醒主线程 -- flag=true
3.子线程开始 -- flag=true
7.主线程开始循环5次 -- flag=true
mainFunction0 -- flag=true
mainFunction1 -- flag=true
mainFunction2 -- flag=true
mainFunction3 -- flag=true
mainFunction4 -- flag=true
8.唤醒子线程 -- flag=false
1.主线程开始 -- flag=false
2.主线程等待 -- flag=false
4.子线程开始循环3次 -- flag=false
subFunction0 -- flag=false
subFunction1 -- flag=false
subFunction2 -- flag=false
5.唤醒主线程 -- flag=true
3.子线程开始 -- flag=true
6.子线程等待 -- flag=true
7.主线程开始循环5次 -- flag=true
mainFunction0 -- flag=true
mainFunction1 -- flag=true
mainFunction2 -- flag=true
mainFunction3 -- flag=true
mainFunction4 -- flag=true
8.唤醒子线程 -- flag=false
1.主线程开始 -- flag=false
2.主线程等待 -- flag=false
4.子线程开始循环3次 -- flag=false
subFunction0 -- flag=false
subFunction1 -- flag=false
subFunction2 -- flag=false
5.唤醒主线程 -- flag=true
7.主线程开始循环5次 -- flag=true
mainFunction0 -- flag=true
mainFunction1 -- flag=true
mainFunction2 -- flag=true
mainFunction3 -- flag=true
mainFunction4 -- flag=true
8.唤醒子线程 -- flag=false

Lock和synchronized的选择

  总结来说,Lock和synchronized有以下几点不同:

  1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;

  2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

  3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;

  4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

  5)Lock可以提高多个线程进行读操作的效率。

  在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。

 

 

练习题2:设计四个线程,其中两个线程每次对变量i加1,另外两个线程每次对i减1.

package com.lianxi;

// 面试题2:设计四个线程,其中两个线程每次对变量i加1,另外两个线程每次对i减1.
public class ThreadTest { 
      
    public static void main(String[] args){ 
    	
    	final ThreadTestFunction f = new ThreadTestFunction();
    	
    	Thread t1 = new Thread(new Runnable(){
    		public void run(){
    			f.add();
    		} 
    	});
    	
    	Thread t2 = new Thread(new Runnable(){
    		public void run(){
    			f.add();
    		} 
    	});
    	
    	Thread t3 = new Thread(new Runnable(){
    		public void run(){
    			f.sub();;
    		} 
    	});
    	
    	Thread t4 = new Thread(new Runnable(){
    		public void run(){
    			f.sub();
    		} 
    	}); 
    	 
    	t1.start();
    	t2.start();
    	t3.start();
    	t4.start();
    }  
}
package com.lianxi;

public class ThreadTestFunction { 
	
	private int i=0;
	
	public synchronized void add(){
		i++;
		System.out.println(Thread.currentThread().getName()+"add:i="+i);
	}
	
	public synchronized void sub(){
		i--;
		System.out.println(Thread.currentThread().getName()+"sub:i="+i);
	}
}

输出结果:

Thread-0add:i=1
Thread-3sub:i=0
Thread-2sub:i=-1
Thread-1add:i=0

练习题3:自己编写代码,实现生产者-消费者模型功能.内容自由发挥,只需要表达思想.

package com.lianxi;

public class ThreadProductTest {

	/**
	 * 面试题3:自己编写代码,实现生产者-消费者模型功能.内容自由发挥,只需要表达思想.
	 * 代码中,自定义一个学生类,有name和age属性,属于共享对象,
	 * 生产者负责为studnet对象赋值,消费者负责打印出student对象的name和age的值,
	 * 当生产者赋值完以后通知消费者来打印,消费者打印完以后,通知生产者重新设置.
	 */
	public static void main(String[] args) { 
		
		final ThreadStudent s = new ThreadStudent();
		
		// 模拟生产者线程类
		Thread inputThread = new Thread(new Runnable(){
			public void run(){ 
				int num = 10;
				while(num>0){
					if(num % 2 == 0){
						s.set("刘德华", 56); 
					}else{
						s.set("仓木麻衣", 36); 
					}
					num--;
				}  
			}
		},"生产者");
		
		// 模拟消费者线程类
		Thread outputThread = new Thread(new Runnable(){
			public void run(){  
				int num = 10;
				while(num>0){
					s.get();
					num--;
				}  
			}
		},"消费者");
		
		inputThread.start();
		outputThread.start();
	}
	 

}
package com.lianxi;

//学生实体类作为共享资源
public class ThreadStudent { 

	public String name;  // 姓名
	public int age;  // 年龄
	public boolean flag = false;  // 标记变量,判断当前学生对象是否已创建赋值好
	
	//生产者的功能  ,为studnet对象赋值
	public synchronized void set(String name,int age){ 
		if(flag){
			try {
				this.wait();
			} catch (InterruptedException e) { 
				e.printStackTrace();
			}
		} 
		
		this.name = name;
		this.age = age;
		System.out.println(Thread.currentThread().getName()+"  student:name="+name+",age="+age+" -- flag="+flag);
		this.flag = true;
		this.notify(); // 唤醒 消费者线程 
		
	}
	
	// 消费者的功能,打印sutdent对象的内容
	public synchronized void get(){ 
		if(!flag){
			try {
				this.wait();
			} catch (InterruptedException e) { 
				e.printStackTrace();
			} 
		}
		System.out.println(Thread.currentThread().getName()+"  student:name="+name+",age="+age+" -- flag="+flag);
		
		this.flag = false;
		this.notify(); // 唤醒 生产者线程
		
	}

}

输出结果:

生产者  student:name=刘德华,age=56 -- flag=false
消费者  student:name=刘德华,age=56 -- flag=true
生产者  student:name=仓木麻衣,age=36 -- flag=false
消费者  student:name=仓木麻衣,age=36 -- flag=true
生产者  student:name=刘德华,age=56 -- flag=false
消费者  student:name=刘德华,age=56 -- flag=true
生产者  student:name=仓木麻衣,age=36 -- flag=false
消费者  student:name=仓木麻衣,age=36 -- flag=true
生产者  student:name=刘德华,age=56 -- flag=false
消费者  student:name=刘德华,age=56 -- flag=true
生产者  student:name=仓木麻衣,age=36 -- flag=false
消费者  student:name=仓木麻衣,age=36 -- flag=true
生产者  student:name=刘德华,age=56 -- flag=false
消费者  student:name=刘德华,age=56 -- flag=true
生产者  student:name=仓木麻衣,age=36 -- flag=false
消费者  student:name=仓木麻衣,age=36 -- flag=true
生产者  student:name=刘德华,age=56 -- flag=false
消费者  student:name=刘德华,age=56 -- flag=true
生产者  student:name=仓木麻衣,age=36 -- flag=false
消费者  student:name=仓木麻衣,age=36 -- flag=true

练习题4:现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?

package com.lianxi;

import java.util.Date;

public class ThreadSortTest {

	/**
	 * 现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?
	 */
	public static void main(String[] args) { 
		
		Thread t1 = new Thread(new Runnable(){
			public void run(){
				System.out.println(Thread.currentThread().getName()+" -- "+System.currentTimeMillis());
			} 
		},"t1");
		
		Thread t2 = new Thread(new Runnable(){
			public void run(){
				System.out.println(Thread.currentThread().getName()+" -- "+System.currentTimeMillis());
			} 
		},"t2");
		
		Thread t3 = new Thread(new Runnable(){
			public void run(){
				System.out.println(Thread.currentThread().getName()+" -- "+System.currentTimeMillis());
			} 
		},"t3");
		
		t1.start();
		try {
			t1.join();  // t1.join()需要等t1.start()执行之后执行才有效果
		} catch (InterruptedException e) { 
			e.printStackTrace();
		}
		t2.start();
		try {
			t2.join();  // t2.join()需要等t2.start()执行之后执行才有效果
		} catch (InterruptedException e) { 
			e.printStackTrace();
		}
		t3.start();

	}

}

输出结果:

t1 -- 1540456352889
t2 -- 1540456352889
t3 -- 1540456352890

转载请注明出处:https://blog.csdn.net/yuzongtao/article/details/83378538

你可能感兴趣的:(java)