程序:程序是为了完成某个特定任务,使用某种计算机语言编写的一组指令的有序集合。
进程:进程是具有一定独立功能的程序的运行过程,是系统进行资源分配和任务调度的一个独立单位。
线程:线程是进程中的一个独立执行线索,是CPU调度和分配的基本单位,自己基本上不拥有系统资源。
创建线程的四种方式
1、继承Thread类
覆盖定义run方法,启动线程必须是start方法,收到Java当中单根继承体系的影响,一般并不使用。
public static void main(String[] args) {
MyThread t = new MyThread();
t.start();
}
2、实现Runnable接口:定义独立类,定义内部类
run方法不能有返回值,不能抛出异常
public static void main(String[] args) {
Thread t=new Thread(new YyThread());
t.start();
}
3、使用Callable和Future接口创建线程
Callable接口call方法可以有返回值,可以抛出异常
Future接口的实现FutureTask实现类也实现了Runnable接口
public static void main(String[] args) throws Exception {
FutureTask[] arr = new FutureTask[10];
for (int i = 0; i < 10; i++) {
int begin = i * 100 + 1;
int end = (i + 1) * 100;
arr[i] = new FutureTask<>(new MyCallable(begin, end));
Thread t = new Thread(arr[i]);
t.start();
}
// 获取最终计算结果
int res = 0;
for (int i = 0; i < arr.length; i++)
res += ((Integer) arr[i].get()); // 通过FutureTask提供的get方法获取Callable实现类中call方法的执行结果
System.out.println("1+2+3+...+1000=" + res);
}
4、使用线程池创建线程
public static void main(String[] args) throws Exception{
ExecutorService es = Executors.newFixedThreadPool(3);
// 计算1+2+3+...+1000,启动10个工作任务
Future[] fs = new Future[10];
for (int i = 0; i < 10; i++) {
int begin = i * 100 + 1;
int end = (i + 1) * 100;
Callable<Integer> caller = new MyCallable(begin, end);
fs[i] = es.submit(caller);
}
int res = 0;
for (int i = 0; i < fs.length; i++) {
Object kk = fs[i].get();
if (kk != null && kk instanceof Integer) {
res += (Integer) kk;
}
}
es.shutdown();
System.out.println("1+2+3+...+1000=" + res);
}
volatile关键字
volatile关键字是Java提供的一种轻量级的同步手段,因为volatile只能保证多线程内存的可见性,不能保证操作的原子性。
volatile 关键字实际上是Java 提供的一种轻量级的同步手段,因为volatile 只能保证多线程内存可见性,不能保证操作的原子性。任何被volatile 修改的变量,都不会进行副本的拷贝,任何操作都即使写在主内存中。因此使用volatile 修改的变量的修改,所有线程都立刻可以看到。
使用volatile 的限制:
1、对变量的写操作不依赖于当前值
2、该变量没有包含在具有其它变量的不变式中
volatile 的特性:
1、保证可见性
2、保证有序性
3、部分原子性,针对volatile 变量的符合操作不具备原子性
public calss Test{
private volatile int a;
public void add(int count){
this.a=a+count;
}
}
sleep方法
Thread类中定义的方法,可以阻塞当前线程,是静态方法。
sleep(long)让当前线程休眠等待指定的时间,单位为ms,如果需要可以通过interrupt方法来唤醒休眠的线程。
例如:实现一个时间显示,每隔一秒钟更新一次显示
public static void main(String[] args) {
DateFormat fs = new SimpleDateFormat("yyyy-MM-ddE HH:mm:ss");
while(true){
Date now = new Date();
String ss = fs.format(now);
System.out.println(ss);
try {
TimeUnit.SECONDS.sleep(1);//休眠一秒,等价于Thread.sleep(1000)
} catch (Exception e) {
e.printStackTrace();
}
}
}
提前唤醒休眠的线程:
需要通过interrupt方法实现,会产生一个InterruptedException异常
如:
public static void main(String[] args)throws Exception {
DateFormat fs = new SimpleDateFormat("yyyy-MM-ddE HH:mm:ss");
Thread t1 = new Thread(() -> {
while (true) {
Date now = new Date();
String ss = fs.format(now);
System.out.println(ss);
try {
Thread.sleep(1000);//休眠1s
} catch (Exception e) {
e.printStackTrace();
}
}
});
t1.start();
Thread.sleep(500);
t1.interrupt();//用于唤醒处于休眠状态的线程
}
wait方法
wait方法实在Object类中定义的方法,作用是使当前线程进入等待队列,同时它会使当前线程释放锁持有的锁,直到有其它线程调用此对象的notify或者notifyAll方法进行唤醒
join方法
join方法作用是进行线程的同步处理,可以使得线程之间的并行执行转换为串行执行
synchronized关键字
作用:保证一个时刻点上只有一个线程在执行,不会出现并发的情况,到达排队执行的目的