一: 进程同步是进程之间直接的相互作用,是合作进程间有意识的行为,典型的例子是公共汽车上司机与售票员的合作。只有当售票员关门之后司机才能启动车辆,只有司机停车之后售票员才能开车门。司机和售票员的行动需要一定的协调。同样地,两个进程之间有时也有这样的依赖关系,因此我们也要有一定的同步机制保证它们的执行次序。
问题一:wait(),notify(),notifyAll() 这些方法为什么会定义在Object类中呢?
答:这些方法好像就属于线程的方法,但是Thread类中并没有这些方法,多线程中同步锁对象:任意的Java类这些方法都和锁对象有关系,所以定义在Object类
答:对于sleep()方法,我们首先要知道该方法是属于Thread类中的。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当 指定的时间到了又会自动恢复运行状态。在调用sleep()方法的过程中,线程不会释放对象锁。
而wait()方法,则是属于Object类中的。 当调用wait()方法的时候,线程会放弃对象锁,进入等待此 对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备
获取对象锁进入运行状态。
问题三: 同步机制(同步代码块/同步方法) 此时出现了非线程安全问题,因为两个线程同时访问一个没有同步 的方法,如果这两个线程同时操作业务对象中的实例变量,就有可能出现非线程安全问题。
答:解决方案在开发中,使用synchronized(Lock锁也可以)同步代码块将多条语句对共享数据的操作包起来! 只需要在 public void run()前面加synchronized关键词即可。
注:关于Lock对象和synchronized关键字的选择:
ReentrantLock() : 创建一个ReentrantLock实例
lock() : 获得锁
unlock() : 释放锁
二: 线程组:程组表示一个线程的集合。此外,线程组也可以包含其他线程组。
【示例程序】
public static void main(String[] args) {
//获取线程组的名称
// method1();
//如何给多个线程设置一个线程组名称呢?
method2();
}
private static void method2() {
// public ThreadGroup(String name)构造一个新线程组
ThreadGroup tg = new ThreadGroup("main-新的线程组") ;
MyThread my = new MyThread() ;
// Thread(ThreadGroup group, Runnable target, String name)
Thread t1 = new Thread(tg, my, "线程1") ;
Thread t2 = new Thread(tg, my, "线程2") ;
//直接获取线程组名称
System.out.println(t1.getThreadGroup().getName());
System.out.println(t2.getThreadGroup().getName());
}
private static void method1() {
MyThread my = new MyThread() ;
//创建线程类对象
Thread t1 = new Thread(my, "线程1") ;
Thread t2 = new Thread(my, "线程2") ;
//public final ThreadGroup getThreadGroup()返回该线程所属的线程组
ThreadGroup tg1 = t1.getThreadGroup() ;
ThreadGroup tg2 = t2.getThreadGroup() ;
//public final String getName():返回线程组的名称
System.out.println(tg1.getName()); //main
System.out.println(tg2.getName());//main
//所有的线程它默认的线程组名称:main(主线程)
System.out.println(Thread.currentThread().getThreadGroup().getName());//main
}
}
三: 线程池(某个线程执行完毕,反复利用线程对象
线程池:多个线程执行完毕,它会重新回到线程池中,等待被利用,不会变成垃圾!
和线程池有关的类
类 Executors: 一种工厂类
方法:
和线程池的创建有关系
public static ExecutorService newFixedThreadPool(int nThreads)
创建一个可重用固定线程数的线程池
ExecutorService:可以执行异步任务
创建一个线程池,执行接口中的方法
提交:Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)提交一个返回值的任务用于执行,返回一个表示任务的 未决结果的 Future
Future:接口(Future 表示异步计算的结果)
线程池调用完毕可以关闭的
void shutdown():关闭之前,会提交刚才的任务
【示例程序】:主程序分别计算每个线程的求和!
package org.westos_15;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class ExecutorsTest {
public static void main(String[] args) throws InterruptedException,ExecutionException {
//创建线程池对象
ExecutorService pool = Executors.newFixedThreadPool(2) ;
//提交任务
Future<Integer> f1 = pool.submit(new MyCallable(100)) ;
Future<Integer> f2 = pool.submit(new MyCallable(200)) ;
//V get():获取结果
Integer i1 = f1.get() ;
Integer i2 = f2.get() ;
System.out.println(i1);
System.out.println(i2);
//关闭线程池
pool.shutdown();
}
}
子程序
package org.westos_15;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {
//定义个变量
private int number ;
public MyCallable(int number) {
this.number = number;
}
@Override
public Integer call() throws Exception {
//定义最终结果变量
int sum = 0 ;
for(int x =1 ; x <=number ; x ++) {
sum +=x ;
}
return sum;
}
}