Java多线程经典编程题
Java多线程经典编程题
1. 要求线程a执行完才开始线程b, 线程b执行完才开始线程
package com.example.javatest.theardTest.MultiThreadAlgorithm;
/**
- 要求线程a执行完才开始线程b, 线程b执行完才开始线程
- join()解释:https://blog.csdn.net/qq_18505715/article/details/79795728
- wait() 和 notify() 解释:https://blog.csdn.net/chaozhi_guo/article/details/50249177
- join()的作用:主要作用是同步,它可以使得线程之间的并行执行变为串行执行。在A线程中调用了B线程的join()方法时,表示只有当B线程执行完毕时,A线程才能继续执行。
- public void joinDemo(){
- //....
- Thread t=new Thread(payService);
- t.start();
- //....
- //其他业务逻辑处理,不需要确定t线程是否执行完
- insertData();
- //后续的处理,需要依赖t线程的执行结果,可以在这里调用join方法等待t线程执行结束
- t.join();
- }
*/
public class T1T2T3 {
public static class PrintThread extends Thread{
PrintThread(String name){
super(name);
}
@Override
public void run() {
for(int i = 0; i < 100; i++){
System.out.println(getName() + " : " + i);
}
}
}
public static void main(String[] args){
PrintThread t1 = new PrintThread("a");
PrintThread t2 = new PrintThread("b");
PrintThread t3 = new PrintThread("c");
try {
t1.start();
t1.join();
t2.start();
t2.join();
t3.start();
t3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
- 我对于join方法的理解:
- join() 的源码:
- public final void join(long millis) throws InterruptedException {
-
synchronized(lock) {
-
...
-
while (isAlive()) {
-
lock.wait(0);
-
}
-
...
-
}
- }
- 其实就是main()线程调用join()后,synchronized(lock)语句块,获得lock的锁,
- 然后判断如果t1线程isAlive(), 就一直lock.wait(), 让自己(main()线程)阻塞住,
- 直到t1线程 !isAlive 后才不wait, 等待着被notify(), 然后t1 die后会调用lock.notifyAll()。
- 注意:这里lock.wait(0)虽然在t1.join()内,但是join()内的代码不是运行在t1线程中,而是运行在main()线程中,
-
t1线程中运行的是其run()方法内的代码。
*/
2. 两个线程轮流打印数字,一直到100
package com.example.javatest.theardTest.MultiThreadAlgorithm;
/**
* 两个线程轮流打印数字,一直到100
*
* Java的wait()、notify()学习:
* https://blog.csdn.net/boling_cavalry/article/details/77995069
https://blog.csdn.net/boling_cavalry/article/details/77793224 wait()和notify()的通常用法
*/
public class TakeTurnsPrint {
public static class TakeTurns {
private static boolean flag = true;
private static int count = 0;
public synchronized void print1() {
for (int i = 1; i <= 50; i++) {
while (!flag) {
try {
System.out.println("print1: wait before");
wait();
System.out.println("print1: wait after");
} catch (InterruptedException e) {
}
}
System.out.println("print1: " + ++count);
flag = !flag;
notifyAll();
}
}
public synchronized void print2() {
for (int i = 1; i <= 50; i++) {
while (flag) {
try {
System.out.println("print2: wait before");
wait();
System.out.println("print2: wait after");
} catch (InterruptedException e) {
}
}
System.out.println("print2: " + ++count);
flag = !flag;
notifyAll();
}
}
}
public static void main(String[] args){
TakeTurns takeTurns = new TakeTurns();
new Thread(new Runnable() {
@Override
public void run() {
takeTurns.print1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
takeTurns.print2();
}
}).start();
}
}
3. 写两个线程,一个线程打印1~ 52,另一个线程打印A~Z,打印顺序是12A34B…5152Z
package com.example.javatest.theardTest.MultiThreadAlgorithm;
/**
* 两线程,一个打印数字从1到52,另一个打印字母从A到Z,输出:12A34B56C...5152Z
*/
public class TakeTurnsPrint2 {
private boolean flag;
private int count;
public synchronized void printNum() {
for (int i = 0; i < 26; i++) {
while (flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
flag = !flag;
System.out.print(++count);
System.out.print(++count);
notify();
}
}
public synchronized void printLetter() {
for (int i = 0; i < 26; i++) {
while (!flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
flag = !flag;
System.out.print((char) (65 + i));
notify();
}
}
public static void main(String[] args) {
TakeTurnsPrint2 turnsPrint2 = new TakeTurnsPrint2();
new Thread(new Runnable() {
@Override
public void run() {
turnsPrint2.printNum();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
turnsPrint2.printLetter();
}
}).start();
}
}
4. 编写一个程序,启动三个线程,三个线程的ID分别是A,B,C;,每个线程将自己的ID值在屏幕上打印5遍,打印顺序是ABCABC…
package com.example.javatest.theardTest.MultiThreadAlgorithm;
/**
* 编写一个程序,启动三个线程,三个线程的ID分别是A,B,C;,每个线程将自己的ID值在屏幕上打印5遍,打印顺序是ABCABC...
*/
public class ABCABCABC {
private int flag = 0;
public synchronized void printA() {
for(int i = 0; i < 5; i++) {
while (flag != 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
flag = 1;
System.out.print("A");
notifyAll();
}
}
public synchronized void printB() {
for(int i = 0; i < 5; i++) {
while (flag != 1) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
flag = 2;
System.out.print("B");
notifyAll();
}
}
public synchronized void printC() {
for(int i = 0; i < 5; i++) {
while (flag != 2) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
flag = 0;
System.out.print("C");
notifyAll();
}
}
public static void main(String[] args) {
ABCABCABC abcabcabc = new ABCABCABC();
new Thread(new Runnable() {
@Override
public void run() {
abcabcabc.printA();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
abcabcabc.printB();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
abcabcabc.printC();
}
}).start();
}
}
5. 编写10个线程,第一个线程从1加到10,第二个线程从11加20…第十个线程从91加到100,最后再把10个线程结果相加。
/**
* 编写10个线程,第一个线程从1加到10,第二个线程从11加20…第十个线程从91加到100,最后再把10个线程结果相加
*/
public class TenThreadSum {
public static class SumThread extends Thread{
int forct = 0; int sum = 0;
SumThread(int forct){
this.forct = forct;
}
@Override
public void run() {
for(int i = 1; i <= 10; i++){
sum += i + forct * 10;
}
System.out.println(getName() + " " + sum);
}
}
public static void main(String[] args) {
int result = 0;
for(int i = 0; i < 10; i++){
SumThread sumThread = new SumThread(i);
sumThread.start();
try {
sumThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
result = result + sumThread.sum;
}
System.out.println("result " + result);
}
}
6. 三个窗口同时卖票
/**
* 三个窗口同时卖票
*/
/**
* 票
*/
class Ticket {
private int count = 1;
public void sale() {
while (true) {
synchronized (this) {
if (count > 200) {
System.out.println("票已经卖完啦");
break;
} else {
System.out.println(Thread.currentThread().getName() + "卖的第 " + count++ + " 张票");
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 售票窗口
*/
class SaleWindows extends Thread {
private Ticket ticket;
public SaleWindows(String name, Ticket ticket) {
super(name);
this.ticket = ticket;
}
@Override
public void run() {
super.run();
ticket.sale();
}
}
public class TicketDemo {
public static void main(String[] args) {
Ticket ticket = new Ticket();
SaleWindows windows1 = new SaleWindows("窗口1", ticket);
SaleWindows windows2 = new SaleWindows("窗口2", ticket);
SaleWindows windows3 = new SaleWindows("窗口3", ticket);
windows1.start();
windows2.start();
windows3.start();
}
}
7. 生产者消费者
7.1 synchronized方式
public class FruitPlateDemo {
private final static String LOCK = "lock";
private int count = 0;
private static final int FULL = 10;
public static void main(String[] args) {
FruitPlateDemo fruitDemo1 = new FruitPlateDemo();
for (int i = 1; i <= 5; i++) {
new Thread(fruitDemo1.new Producer(), "生产者-" + i).start();
new Thread(fruitDemo1.new Consumer(), "消费者-" + i).start();
}
}
class Producer implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (LOCK) {
while (count == FULL) {
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("生产者 " + Thread.currentThread().getName() + " 总共有 " + ++count + " 个资源");
LOCK.notifyAll();
}
}
}
}
class Consumer implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (LOCK) {
while (count == 0) {
try {
LOCK.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费者 " + Thread.currentThread().getName() + " 总共有 " + --count + " 个资源");
LOCK.notifyAll();
}
}
}
}
}
7.2 ReentrantLock方式 (可以保证顺序)
public class Demo1 {
private int count = 0;
private final static int FULL = 10;
private Lock lock;
private Condition notEmptyCondition;
private Condition notFullCondition;
{
lock = new ReentrantLock();
notEmptyCondition = lock.newCondition();
notFullCondition = lock.newCondition();
}
class Producer implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
while(count == FULL) {
try {
notFullCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("生产者 " + Thread.currentThread().getName() + " 总共有 " + ++count + " 个资源");
notEmptyCondition.signal();
} finally {
lock.unlock();
}
}
}
}
class Consumer implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
lock.lock();
try {
while(count == 0) {
try {
notEmptyCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费者 " + Thread.currentThread().getName() + " 总共有 " + --count + " 个资源");
notFullCondition.signal();
} finally {
lock.unlock();
}
}
}
}
public static void main(String[] args) {
Demo1 demo1 = new Demo1();
for (int i = 1; i <= 5; i++) {
new Thread(demo1.new Producer(), "生产者-" + i).start();
new Thread(demo1.new Consumer(), "消费者-" + i).start();
}
}
}
7.3 BlockingQueue方式
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Demo2 {
private int count = 0;
private BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
public static void main(String[] args) {
Demo2 demo2 = new Demo2();
for (int i = 1; i <= 5; i++) {
new Thread(demo2.new Producer(), "生产者-" + i).start();
new Thread(demo2.new Consumer(), "消费者-" + i).start();
}
}
class Producer implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
queue.put(1);
System.out.println("生产者 " + Thread.currentThread().getName() + " 总共有 " + ++count + " 个资源");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
queue.take();
System.out.println("消费者 " + Thread.currentThread().getName() + " 总共有 " + --count + " 个资源");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
8. 交替打印两个数组
package com.example.javatest.theardTest.MultiThreadAlgorithm;
public class TwoArr {
int[] arr1 = new int[]{1, 3, 5, 7, 9};
int[] arr2 = new int[]{2, 4, 6, 8, 10};
boolean flag;
public synchronized void print1(){
for(int i= 0; i < arr1.length; i++){
while (flag){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
flag = !flag;
System.out.println(arr1[i]);
notifyAll();
}
}
public synchronized void print2(){
for(int i= 0; i < arr2.length; i++){
while (!flag){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
flag = !flag;
System.out.println(arr2[i]);
notifyAll();
}
}
public static void main(String[] args) {
TwoArr twoArr = new TwoArr();
new Thread(new Runnable() {
@Override
public void run() {
twoArr.print1();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
twoArr.print2();
}
}).start();
}
}
9. 使用多线程,模拟龟兔赛跑的场景。
//模拟龟兔百米赛跑
public class ThreadTest1 extends Thread{
@Override
public void run() {
try {
pao();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void pao() throws InterruptedException {
for(int i=1;i<=10;i++) {
System.out.println(Thread.currentThread().getName()+"打卡:"+i+"米");
Thread.sleep(1000);
}
}
}
public class ThreadTest2 {
public static void main(String[] args) {
Thread th1=new ThreadTest1();
Thread th2=new ThreadTest1();
th1.setName("龟");
th2.setName("兔");
th1.start();
th2.start();
}
}
10. 编写一个有两个线程的程序,第一个线程用来计算2~100000之间的素数的个数,第二个线程用来计算100000~200000之间的素数的个数,最后输出结果。
//线程类,以及判断素数的方法
public class ThreadTest3 implements Runnable {
@Override
public void run() {
int a=fun1();
System.out.println("一素数个数:"+a);
}
private static int fun1() {
int sum = 0;// 素数个数
for (int i = 2; i <= 100000; i++) {// 某个数
int j=2;
while(i%j!=0) {
j++;
}
if(j==i) {
sum++;
}
}
return sum;
}
}
public class ThreadTest5 implements Runnable{
@Override
public void run() {
int a=fun2();
System.out.println("二素数个数:"+a);
}
private static int fun2() {
int sum = 0;// 素数个数
for (int i = 100000; i <= 200000; i++) {// 某个数
int j=2;
while(i%j!=0) {
j++;
}
if(j==i) {
sum++;
}
}
return sum;
}
}
public class ThreadTest4 {
public static void main(String[] args) {
ThreadTest3 th=new ThreadTest3();
Thread th1=new Thread(th);
th1.start();
ThreadTest5 th2=new ThreadTest5();
Thread th3=new Thread(th2);
th3.start();
}
}
11. 使用多线程实现多个文件同步复制功能,并在控制台显示复制的进度,进度以百分比表示。例如:把文件A复制到E盘某文件夹下,在控制台上显示“XXX文件已复制10%”,“XXX文件已复制20%”……“XXX文件已复制100%”,“XXX复制完成!”
//重点:java.text.DecimalFormat的使用(格式化十进制数)
package two;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.text.DecimalFormat;
public class CopyFile extends Thread{
public File older;//源文件路径
public File newer;//目标文件路径
//构造函数把路径封装成文件
public CopyFile(String older, String newer) {
this.older = new File(older);
this.newer = new File(newer);
}
@Override
public void run() {
FileInputStream fis=null;
FileOutputStream fos=null;
try {
fis=new FileInputStream(older);
fos=new FileOutputStream(newer);
long len=older.length();//获取源文件的长度 跟 fis.available()的结果
//文件大小的十分之一
byte[] b=new byte[(int) (older.length()/10)];//声明一个字节数组,每次读取的数据存到这里
int length=0;//返回每次读取的数据长度
System.out.println(len);
double temp=0;
DecimalFormat df=new DecimalFormat("##%");
//最多将b.length个字节读入一个byte数组中,也就是每次读1/10个字节,然后循环,直到读到问价尾
while((length = fis.read(b)) !=-1) {//读到文件尾会返回-1
fos.write(b, 0, length);//把每次读取的内容,输出到目标路径文件中
temp +=length;//把每次读取的数据长度累加
double d=temp/len;//计算出已经读取的长度占文件总长度的比率
int jd=(int) d;
if(jd%10==0) {
System.out.println(older.getName()+"文件复制了:"+df.format(d));//将小数给格式化
}
System.out.println(older.getName()+"文件已复制了:"+d);
}
System.out.println(older.getName()+"复制完毕!");
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
fis.close();
fos.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
package two;
public class CopyTest {
public static void main(String[] args) {
//两个线程实例
CopyFile cf1=new CopyFile("G://金泰妍.MP3", "F://金泰妍.MP3");
CopyFile cf2=new CopyFile("G://GD.MP3", "F://GD.MP3");
cf1.start();
cf2.start();
}
}
12. 设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。考虑到线程的安全性写出程序。
package test.one;
//4、设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。考虑到线程的安全性写出程序。
//使线程同步
public class Test1 {//一个主线程
private int j;//变量j
public static void main(String[] args) {
Test1 t=new Test1();
Add add=t.new Add();//内部类的实例
Sub sub=t.new Sub();
for(int i=0;i<2;i++){//循环两边创建四个线程,两加两减
Thread t1=new Thread(add);
t1.start();
Thread t2=new Thread(sub);
t2.start();
}
}
//考虑线程安全的问题,为方法加synchronized关键字,保证一时间只有一个线程操作该方法
private synchronized void add(){
j++;
System.out.println(Thread.currentThread().getName()+":"+j);
}
private synchronized void sub(){
j--;
System.out.println(Thread.currentThread().getName()+":"+j);
}
class Add implements Runnable{//线程,成员内部类无条件访问外部类的所有成员
//线程调用了j+的方法
@Override
public void run() {
for (int i=0;i<10;i++){
add();
}
}
}
class Sub implements Runnable{//线程,同上
//线程调用了j-的方法
@Override
public void run() {
for (int i=0;i<10;i++){
sub();
}
}
}
}