目录
练题1:编写程序实现,子线程循环3次,接着主线程循环5次,接着再子线程循环3次,主线程循环5次,如此反复,循环3次.
练习题2:设计四个线程,其中两个线程每次对变量i加1,另外两个线程每次对i减1.
练习题3:自己编写代码,实现生产者-消费者模型功能.内容自由发挥,只需要表达思想.
练习题4:现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?
第一种实现方式:使用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。所以说,在具体使用时要根据适当情况选择。
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
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
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