一. 实现多线程的方式:
1.继承 Thread 类。
创建一个继承 Thread 类的继承类。
重写 run() 方法。
创建继承 Thread 类的对象。
调用 start() 方法。
启动线程时不可直接调用 run() 方法 ,需要使用 start() 方法启动线程。
2.实现 Runnable 接口。
创建一个实现 Runnable 接口的实现类。
重写 run() 方法。
创建 Runnable 接口实现类的对象。
创建 Thread 对象,将 Runnable 接口实现类的对象作为参数传递到 Thread 类的构造器中。
使用 Thread 对象调用 start() 方法。
3.实现 Callable 接口。
创建一个实现 Callable 接口的实现类。
实现 call() 方法。
创建 Callable 接口实现类的对象。
创建FutureTask对象 ,将 Callable 接口实现类的对象作为参数传到 FutureTask 的构造器中。
创建 Thread 类,将 FutureTask 对象作为参数传到 Thread 构造器中。
使用 Thread 对象调用 start() 方法。
4.使用线程池
创建一个 ExecutorService 对象,并指定线程数量。
创建接口实现类的对象。
将接口实现类对象,作为参数传到适用于 Runnable 的 execute() 方法,或适用于 Callable 的 submit() 方法中。
关闭线程池,使用 shutdown() 方法。
5.方式对比:
使用继承这种方式,有单继承的局限性。 而实现的这种方式,可以再实现其他的接口,更适合来处理多个线程有共享数据的情况。
继承 Thread 类和实现 Runnable 接口这两种方式,都需重写run() 方法。
实现 Callable 接口,相对于实现 Runnable 接口更为强大:
1.call() 方法,可以有返回值。
2.call() 方法,可以抛出异常,被外面捕获,获取异常信息。
3.Callnable 接口是支持泛型的。
使用线程池,可以减少创建新线程的时间,提高相应速度。
线程池中的线程可重复利用,降低资源的消耗,另外方便了线程的管理。
二.解决线程安全的方式:
#1.使用synchronized 代码块。
创建同步监视器(任意对象)。
synchronized(同步监视器 ){
需要被同步的代码
}
2.使用synchronized 方法。
共享数据在方法中,就可以使用synchronized方法,
该方法的同步监视器为当前类。
3.使用Lock锁。
实例化 ReentrantLock ,调用 lock 方法锁定,调用 unlock 方法解锁。
使用的是继承的方式,来实现多线程,在解决线程安全问题时,为了避免产生多个锁,需要加static关键字。
synchronized 执行完相应内容后,会自动释放锁。
lock则需要自己去开启锁(lock),关闭锁(unlock)。
三:阻塞线程方法:
1.sleep();
此方法使线程在指定的时间内,处于阻塞状,同时不会释放同步监视器。
2.wait();
此方法使线程进入阻塞状态,同时释放同步监视器,
3.notify();
此方法会唤醒一个被wait的线程,如果有多个,会按照线程优先级,唤醒一个被wait的线程。
4.notifyAll();
此方法,会唤醒所有被wait的线程。
其中 wait() notify() notifyAll() 这三个方法,必须使用在同步代码块或同步方法中,调用者也必须为同步代码块或同步方法中的同步监视器,否则会出现异常。