1、程序、进程、线程三者的关系
程序:一组指令的集合,是静态的实体,没有执行的含义。(程序未运行时,只是占据一块内存,不占据内存)
进程:程序包含进程,一个程序可以有多个进程,或者一个进程都没有。但是一个进程肯定与一个程序相对应,并且只有一个。进程是一个动态的实体,有自己的生命周期,是资源分配的单位。
线程:进程包含线程,一个进程可以有多个线程。线程会共享属于进程的共享代码和数据空间,是调度和执行的单位。
2、java中多线程实现(一般推荐使用Runnable接口)
2.1、继承Thread类,重写run()方法
public class TestThread extends Thread {
public void run() {//线程的入口点,必须重写
for (int i = 0; i < 20; i++) {
System.out.println(this.getName() + ":"+i);
}
}
public static void main(String[] args) {
TestThread TestThread1 = new TestThread();
TestThread1.start();//线程调用,不一定立即调用,一般交给cpu执行
TestThread TestThread2 = new TestThread();
TestThread2.start();
}
}
2.2、实现Runnable接口,重写run()方法
由于不是继承的Thread类,所以没有start()方法,需要通过Thread调用
public class TestRunnable implements Runnable {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + ":"+i);
}
}
public static void main(String[] args) {
//把Runnable接口的对象作为参数传入Thread,进而使用Thread的start()方法。
Thread thread1 = new Thread(new TestRunnable(),"线程1");//写法一:第二个参数可以传入线程名称
thread1.start();
TestRunnable thread2 = new TestRunnable();//写法二
new Thread(thread2).start();
}
}
2.3、实现Callable接口,重写call()方法(了解即可)
属于高级并发编程juc,比前两种方法多了:(1)可以进行异常处理(2)有返回值
public class TestCallable implements Callable<Boolean> {
public Boolean call() throws Exception {//线程的入口点,重写call()方法
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+ ":" +i);
}
return true;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
TestCallable testCallable1 = new TestCallable();
TestCallable testCallable2 = new TestCallable();
TestCallable testCallable3 = new TestCallable();
//创建执行服务,并传入线程池数量
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> result1 = ser.submit(testCallable1);
Future<Boolean> result2 = ser.submit(testCallable2);
Future<Boolean> result3 = ser.submit(testCallable3);
//获取结果
boolean r1 = result1.get();
System.out.println(r1);
boolean r2 = result2.get();
boolean r3 = result3.get();
//关闭服务
ser.shutdownNow();
}
}
3、线程状态
新生、就绪、运行、阻塞、死亡
4、多线程方法
Thread thread = new Thread(new TestRunnable());
thread.start();
thread.isAlive();//判断线程是否终止着
thread.getPriority();//获取线程优先级
thread.setPriority(3);//设置线程优先级,范围从1到10,线程默认优先级是5,值越大优先级越高
thread.setName("线程");//给线程命名
thread.getName();//取得线程名
thread.currentThread();//取得当前运行的线程对象
thread.stop();//线程终止:目前已废弃,一般使用boolean终止变量,通过写一个停止方法(如:stop),并将这个变量置为false,通过调用这个方法进而终止线程的运行。
Thread.sleep(1000);线程休眠:让正在运行的线程进入阻塞状态,参数单位毫秒
Thread.yield();//线程暂停:让正在运行的线程重新直接进入就绪状态
//线程联合:线程A在运行期间,调用线程B的join()方法(如thread2.join()),这样,线程A就必须等待线程B执行完毕后,才能继续执行。
thread.join();//将thread加入另一个线程中,需写在另一个线程中,先执行完thread线程才能执行外面的线程
5、线程同步( synchronized)
避免了同一个数据对象被多个线程同时访问造成的这种问题。
实现:可以给方法加入synchronized关键字来声明,也可以使用synchronized块。一般使用synchronized块来实现
synchronized(Object)//需要获得Object对象的“锁”才有资格运行,在同一时刻只能被一个线程使用。
{
//允许访问控制的代码
}
6、死锁
多个线程各自占有一些共享资源,且必须等待其他线程占有的资源才能进行,进而造成死锁。