荐 Java高级阶段之多线程之二
程序员文章站
2022-06-28 18:56:21
JDK5.0以后新增加的两种创建多线程的方式:方式一:实现Callable接口创建一个实现了Callable接口的实现类;实现call()方法,将此线程要进行的操作放入其中;创建Callable接口实现类的对象;将此Callable接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask的对象;将FutureTask的对象作为参数传递到Thread构造器中;创建Thread的对象,并调用start()方法;实现及其代码如下:class NumThread i...
JDK5.0以后新增加的两种创建多线程的方式:
方式一:实现Callable接口
- 创建一个实现了Callable接口的实现类;
- 实现call()方法,将此线程要进行的操作放入其中;
- 创建Callable接口实现类的对象;
- 将此Callable接口实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask的对象;
- 将FutureTask的对象作为参数传递到Thread构造器中;
- 创建Thread的对象,并调用start()方法;
实现及其代码如下:
class NumThread implements Callable{
private int sum = 0;
@Override
public Object call() throws Exception {
for (int i = 1; i <= 100 ; i++) {
if (i % 2==0) {
System.out.println(i);
sum += i;
}
}
return sum;
}
}
public class ThreadNew {
public static void main(String[] args) {
NumThread numThread = new NumThread();
FutureTask futureTask = new FutureTask(numThread);
Thread thread = new Thread(futureTask);
thread.start();
try {
Object sum = futureTask.get(); //get()返回值即为FutureTask构造器参数Callable()实现类重写call()的返回值。
System.out.println("所有偶数的总和为" + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
很多的部门的面试都会涉及到这个方法区创建多线程,因为是JDK5.0以后新出的方法,当然最主要的原因也是最关键的是该方法功能与前2种方式的不同和优势所在:
- call()可以有返回值的;
- call()可以抛出异常,被外面的操作捕获,获取异常的信息;
- Callable是支持泛型的;
- 需要借助FutureTask类,比如获取返回结果;
这样的优势使得在线程创建的方法中拥有很强大的优势所在。
方式二:通过线程池来创建
- 提供指定线程数量的线程池;
- 执行指定的线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象;
- 关闭连接池;
实现及其代码如下:
class pool implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2==0){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
class pool1 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i%2!=0){
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
public class ThreadPool {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);//1.提出指定线程数量的线程池
ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
//设置线程池的属性
//System.out.println(service.getClass());
//service1.setCorePoolSize(15);
//service1.setKeepAliveTime();
//2.执行指定的线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象
service.execute(new pool());//适合使用实现Runnable接口
service.execute(new pool1());
//service.submit(); 这种方式适合用于实现Callable接口
service.shutdown();//3.关闭连接池
}
}
接着补上最后一种去处理线程同步安全问题的方法:
- 实例化ReentrantLock;
- 调用锁定方法:lock();
- 调用解锁的方法:unlock();
实现及其代码如下:
class window1 implements Runnable{
private int ticket = 100;
//1.实例化ReentrantLock
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
//2.调用锁定方法:lock()
lock.lock();
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":卖票,票号为: " + ticket);
ticket--;
} else {
break;
}
}
finally {
//2.调用解锁的方法:unlock()
lock.unlock();
}
}
}
}
public class Window {
public static void main(String[] args) {
window1 w = new window1();
Thread th1 = new Thread(w);
Thread th2 = new Thread(w);
Thread th3 = new Thread(w);
th1.setName("窗口1");
th2.setName("窗口2");
th3.setName("窗口3");
th1.start();
th2.start();
th3.start();
}
}
这里也是通过3个窗口卖票的那个例子来进行去解决的,前面那一篇java高级阶段之多线程其中就有,可以先看上一篇,这个使用lock()方式,使用更加的灵活,因为这种方式也是JDK5.0以后才提出的问题,就放在这一篇*同去探讨。
总结:
最基本的线程创建以及如何去解决线程安全问题的方法和步骤都已经熟悉。我还会总结一篇关于多线程各种方式之间的对比和总结。在面试中可能考的面试题都会涉及,关注我看后续…
创建多线程的方式有4种,继承Thread()方式和实现Rannable()在企业级的适用范围较广,但是其中的实现Callable接口还是要深入了解的,用线程池的方式可以根据企业开发的模板一起使用更加的方便,解决多线程安全的问题有3种,这3种方式可以根据实际的需要去使用。优先的使用顺序:Lock---->同步代码块(已经进入了方法体,分配了相应资源)---->同步方法(在方法体之外)。
以上就是我对多线程的初步了解,我是小白,希望志同道合的朋友们我们可以一起努力,一起加油!!谢谢你长那么帅还给我点赞,喜欢的朋友们可以点赞,有什么问题私信或者留言…
本文地址:https://blog.csdn.net/qq_33981280/article/details/107349006
下一篇: JavaScript 简单的动态表格实现