1.用两个线程分别计算1-100之间偶数的和奇数的和
给定一个很长的数组 (长度 1000w), 通过随机数的方式生成 1-100 之间的整数.
实现代码, 能够创建两个线程, 对这个数组的所有元素求和.
其中线程1 计算偶数下标元素的和, 线程2 计算奇数下标元素的和.
最终再汇总两个和, 进行相加
记录程序的执行时间.
import java.util.Random;
public class Demo5 {
public static void main(String[] args) throws InterruptedException {
long startTime = System.currentTimeMillis();
int total = 1000_0000;
int[] a = new int[total];
Random random = new Random();
for (int i = 0; i < total; i++) {
int num = random.nextInt(100)+1;
a[i] = num;
}
Operation operation = new Operation();
Thread t1 = new Thread(()->{
for (int i = 0; i < total; i+=2) {
operation.addEvenSum(a[i]);
}
});
Thread t2 = new Thread(() ->{
for (int i = 1; i < total; i+=2) {
operation.addOddSum(a[i]);
}
});
t1.start();
t1.join();
t2.start();
t2.join();
long endTime = System.currentTimeMillis();
System.out.println(operation.result());
System.out.println(endTime - startTime +"ms");
}
static class Operation {
long evenSum;
long oddSum;
private void addEvenSum(int num){
evenSum += num;
}
private void addOddSum(int num){
oddSum += num;
}
public long result(){
System.out.println("偶数的和:"+evenSum);
System.out.println("奇数的和:"+oddSum);
return evenSum + oddSum;
}
}
}
2.请说明Thread类中run和start的区别
作用功能不同:
- run方法的作用是描述线程具体要执行的任务;
- start方法的作用是真正的去申请系统线程
运行结果不同:
- run方法是一个类中的普通方法,主动调用和调用普通方法一样,会顺序执行一次;
- start调用方法后, start方法内部会调用Java 本地方法(封装了对系统底层的调用)真正的启动线程,并执行run方法中的代码,run 方法执行完成后线程进入销毁阶段。
3. 请描述 volatile 关键字的作用
volatile关键字的作用主要有如下两个:
- 保证内存可见性:基于屏障指令实现,即当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。
- 保证有序性:禁止指令重排序。编译时 JVM 编译器遵循内存屏障的约束,运行时靠屏障指令组织指令顺序。
注意:volatile 不能保证原子性
4. 每个线程循环 1w 次,累加变量 count 的值,count 默认值为 0,注意线程安全问题。
public class Demo6 {
public static int count = 0;
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
Thread t1 = new Thread(() ->{
for (int i = 0; i < 10000; i++) {
System.out.println("count的值"+count);
synchronized (object){
count++;
}
}
System.out.println("t1线程结束");
});
Thread t2 = new Thread(() ->{
for (int i = 0; i < 10000; i++) {
System.out.println("count的值"+count);
synchronized (object){
count++;
}
}
System.out.println("t2线程结束");
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(count);
}
}
5. 打印ABC按照下列要求
有三个线程,分别只能打印A,B和C
要求按顺序打印ABC,打印10次
输出示例:
ABC
ABC
ABC
ABC
ABC
ABC
ABC
ABC
ABC
ABC
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
Object locker1 = new Object();
Object locker2 = new Object();
Object locker3 = new Object();
Thread t1 = new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
synchronized (locker1){
locker1.wait();
}
System.out.print("A");
synchronized (locker2){
locker2.notify();
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
Thread t2 = new Thread(() ->{
try {
for (int i = 0; i < 10; i++) {
synchronized (locker2){
locker2.wait();
}
System.out.print("B");
synchronized (locker3){
locker3.notify();
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
Thread t3 = new Thread(() ->{
try {
for (int i = 0; i < 10; i++) {
synchronized (locker3){
locker3.wait();
}
System.out.println("C");
synchronized (locker1){
locker1.notify();
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
t1.start();
t2.start();
t3.start();
Thread.sleep(1000);
synchronized (locker1){
locker1.notify();
}
}
}
6.同时启动打印线程名称
有三个线程,线程名称分别为:a,b,c。
每个线程打印自己的名称。
需要让他们同时启动,并按 c,b,a的顺序打印
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
System.out.print(Thread.currentThread().getName()+" ");
},"c");
Thread t2 = new Thread(()->{
try {
t1.join();
}catch (InterruptedException e){
throw new RuntimeException(e);
}
System.out.print(Thread.currentThread().getName()+" ");
},"b");
Thread t3= new Thread(()->{
try {
t2.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.print(Thread.currentThread().getName()+" ");
},"a");
t1.start();
t2.start();
t3.start();
}
}
7.按照要求写一个死锁的代码
提供:可以通过 synchronized 或者 Lock 来实现一个死锁代码。
所谓的死锁就是线程一拥有锁1,线程二拥有锁2,双方在拥有自身锁的同时尝试获取对方的锁,最终两个线程就会进入无线等待的状态,这就是死锁。
Object lock1 = new Object();
Object lock2 = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock1) {
System.out.println(Thread.currentThread().getName() +
":已经获取到锁1");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println(Thread.currentThread().getName() +
":获取到锁2");
}
}
}, "t1");
t1.start();
Thread t2 = new Thread(() -> {
synchronized (lock2) {
System.out.println(Thread.currentThread().getName() + ":获取到锁2");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println(Thread.currentThread().getName() + ":获取到锁1");
}
}
}, "t2");
t2.start();
8.阻塞队列代码编写
class MyBlockingQueue1 {
public String[] data = null;
private int head = 0;
private int tail = 0;
MyBlockingQueue1(int capacity) {
data = new String[capacity];
}
private int size = 0;
void put(String val) throws InterruptedException {
synchronized (this) {
while (size == data.length) {
this.wait();
}
data[tail] = val;
tail++;
if (tail >= data.length) {
tail = 0;
}
size++;
notify();
}
}
String take() throws InterruptedException {
synchronized (this) {
while (size == 0) {
this.wait();
}
String e = data[head];
head++;
if (head == data.length) {
head = 0;
}
size--;
this.notify();
return e;
}
}
public int getSize () {
return size;
}
}
public class Demo4 {
public static void main(String[] args) {
MyBlockingQueue1 queue1 = new MyBlockingQueue1(100);
Thread producer = new Thread(()->{
int n = 0;
while(true){
try {
queue1.put(n+"");
System.out.println("生产"+n);
n++;
}catch (InterruptedException e){
throw new RuntimeException(e);
}
}
});
Thread consumer = new Thread(()->{
while(true){
String n = null;
try {
n = queue1.take();
System.out.println("消费"+n);
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
producer.start();
consumer.start();
}
}