程序、进程、线程
程序(program):程序是为了完成特定的任务,用某种语言编写的一组指令的集合,即之一段静态代码,静态对象
进程(process):进程是程序的一次执行过程,或是正在运行的一段程序。是一个动态的过程。有它自身的产生,存在和消亡的过程 —— 声明周期
进程作为资源分配的单位,系统在运行时,会为每个进程分配不同的内存区域
线程(thread):进程可以进一步细化为线程,是一个程序内部的一条执行路径
线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器
单核CPU与多核CPU
单核CPU:是一种假的多线程,因为在一个时间单元内只能执行一个线程的任务
多核CPU:真正的多线程,一个时间单元内可以执行多个线程的任务,好比多车道,可以同时跑多辆汽车
并行和并发
并行:多个CPU同时执行多个任务。比如:多个人同时做不同的事情
并发:一个CPU同时执行多个任务。比如:秒杀活动,多个人同时执行一件事情
使用多线程的优点 背景:以单核CPU为例,只是用单个线程先后完成多个任务(调用多个方法),肯定要比使用多个线程来完成多个任务用时更短,那么为何还需要多线程呢?
多线程的优点:
提高应用程序的响应。对图形界面更有意义,增强用户体验
提高计算机系统CPU的利用率
改善程序结构。将即长又复杂的进程分为多个线程,独立运行,利于理解和修改
创建线程方式一:继承 Thread 类 获取当前线程的名称
1 Thread.currentThread().getName()
不可以通过调用线程对象的 run 方法来新建线程,如果通过调用 run 方法,则还是在主线程中执行,并没有新建线程
如果想要再新建线程,必须重新创建一个线程对象,使用新的线程对象调用 start 方法。不能再调用已经 start 的线程去执行,这样做程序会抛出异常 IllegalArgumentException
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class MyThread extends Thread { @Override public void run () { for (int i = 1 ; i <= 100 ; i++) { if (i % 2 == 0 ) { System.out.println(Thread.currentThread().getName() + ":" + i); } } } } public class ThreadTest { public static void main (String[] args) { MyThread t1 = new MyThread(); t1.start(); MyThread t2 = new MyThread(); t2.start(); for (int i = 0 ; i < 100 ; i++) { if (i % 2 != 0 ){ System.out.println(Thread.currentThread().getName() + ":" + i + "*****" ); } } } }
继承 Thread 类的课后练习 Thread 练习:创建两个线程,一个线程打印100以内的所有偶数,一个线程打印100以内的所有奇数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class MyThread1 extends Thread { @Override public void run () { for (int i = 1 ; i <= 100 ; i++) { if (i % 2 == 0 ) { System.out.println(Thread.currentThread().getName() + ":" + i); } } } } class MyThread2 extends Thread { @Override public void run () { for (int i = 1 ; i <= 100 ; i++) { if (i % 2 != 0 ) { System.out.println(Thread.currentThread().getName() + ":" + i); } } } } public class ThreadDemo { public static void main (String[] args) { MyThread1 m1 = new MyThread1(); MyThread2 m2 = new MyThread2(); m1.start(); m2.start(); } }
Thread 线程常用方法
start();
启动当前线程,调用当前线程中的 run() 方法
run();
要在 Thread 类的子类中重写此方法,将创建的线程要执行的操作写在这个方法中
currentThread();
静态方法,返回执行当前代码的线程
getName();
获取当前线程的名称
setName();
设置当前线程的名称
yield();
释放当前cpu
的执行权,释放后cup仍然可能重新执行当前的线程
join();
等待其他线程运行完毕。在线程a中执行线程b的join方法,此时线程a进入阻塞状态,直到线程b执行结束,再接着执行线程a
stop();
已过时。强制结束此线程的方法
sleep(long millis);
线程睡眠,让当前正在执行的线程暂停执行,等待指定的毫秒数过后在继续执行。此方法接收的是毫秒
isAlive();
判断某个线程是否还活着,返回时一个布尔值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 class Thread1 extends Thread { public Thread1 (String name) { super (name); } @Override public void run () { for (int i = 0 ; i < 100 ; i++) { if (i % 2 == 0 ) { try { Thread.sleep(10 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + ":" + i); } } } } class Thread2 extends Thread { Thread1 t; public Thread2 (Thread1 t) { this .t = t; this .setName("线程2" ); } @Override public void run () { for (int i = 0 ; i < 100 ; i++) { if (i % 2 != 0 ) { System.out.println(this .getName() + ":" + i); } if (i == 21 ) { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } } } System.out.println(t.getName() + "是否还活着:" + t.isAlive()); } } public class ThreadMethodsTest { public static void main (String[] args) { Thread1 t1 = new Thread1("线程1" ); Thread2 t2 = new Thread2(t1); t1.start(); t2.start(); } }
线程的优先级设置 线程优先级的几个等级,Thread 类中定义了三个优先级常量
Thread.MIN_PRIORITY
,最小的优先级,数值是 1
Thread.NORM_PRIORITY
,默认的优先级,数值是 5
Thread.MAX_PRIORITY
,最大的优先级,数值是 10
优先级可以在 1~10 之间内设置,设置其他等级时直接通过Thread.setPriority()
设置优先级的方法:Thread.setPriority()
,获取优先级的方法:Thread.getPriority()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class MyThread1 extends Thread { @Override public void run () { for (int i = 0 ; i < 100 ; i++) { if (i % 2 == 0 ) { System.out.println(getName() + getPriority() + ":" + i); } } } } public class PriorityTest { public static void main (String[] args) { MyThread1 t = new MyThread1(); t.setName("分线程" ); t.setPriority(Thread.MAX_PRIORITY); t.start(); Thread.currentThread().setPriority(Thread.MIN_PRIORITY); for (int i = 0 ; i < 100 ; i++) { if (i % 2 != 0 ) { System.out.println(Thread.currentThread().getName() + Thread.currentThread().getPriority() + ":" + i); } } } }
创建多线程的方式二:实现 Runnable 接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class MyRunnable 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 RunnableTest { public static void main (String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.setName("线程1" ); thread.start(); Thread thread1 = new Thread(myRunnable); thread1.setName("线程2" ); thread1.start(); } }
两种线程创建方式的对比 开发中,要优先选择使用实现 Runnable 的方式来创建线程
原因:实现的方式没有类的继承的局限性,实现的方式更适合处理多个线程共享数据的情况
相同点:继承 Thread 和实现 Runnable 都需要实现 run 方法,讲线程的操作逻辑写在 run 方法中
线程的生命周期
新建:当一个 Thread 类或其子类的对象被声明创建时,新生成的线程对象处于新建状态
就绪:处于新建状态的线程别 start 后就处于就绪状态,等待 CPU 去分配资源使其运行
运行:当就绪的线程被调度并获得CPU资源时就进入运行状态,run 方法定义了线程的操作和功能
阻塞:在某种特殊的情况下,被人为的挂起或执行输入输出操作时,让出CPU或停止自己的执行,进入阻塞状态
死亡:死亡是线程的最终状态,线程完成了它的全部工作或者被提前强制终止或出现异常导致线程结束。
线程安全问题 当多个线程操作共享的数据时,容易出现线程安全问题,那买票的示例来说明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class MyRunnable implements Runnable { private int ticket = 100 ; @Override public void run () { while (true ){ if (ticket <= 0 ){ break ; } try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖出票号:" + ticket--); } } } public class WindowsTest1 { public static void main (String[] args) { MyRunnable myRunnable = new MyRunnable(); Thread thread1 = new Thread(myRunnable); Thread thread2 = new Thread(myRunnable); Thread thread3 = new Thread(myRunnable); thread1.setName("窗口1" ); thread2.setName("窗口2" ); thread3.setName("窗口3" ); thread1.start(); thread2.start(); thread3.start(); } }
上面的代码执行后会出现下面的情况:出现了重票、错票的问题
这是因为当一个线程进入while循环开始判断时,进入睡眠100毫秒,此时另外一个线程进来判断,这时两个线程都通过了判断,相当于两个线程都操作了同一张票,所以就产生了上面的结果
解决办法,当线程a操作数据时,其他线程不能进来,等待线程a执行完毕后,其他线程才能进来。所以我们可以使用同步代码块的方式来解决线程安全问题
解决安全问题的方法一:使用同步代码块解决实现Runnable的线程安全问题 同步代码的使用结构
1 2 3 synchronized (同步监听器){ 需要被同步的代码 }
同步代码块的使用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 class TicketTest implements Runnable { private int ticketCount = 100 ; Object obj = new Object(); @Override public void run () { while (true ){ synchronized (obj){ try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } if (ticketCount <= 0 ) break ; System.out.println(Thread.currentThread().getName() + "卖出:" + ticketCount); ticketCount--; } } } } public class SynchronizedTest { public static void main (String[] args) { TicketTest t = new TicketTest(); Thread thread1 = new Thread(t); Thread thread2 = new Thread(t); Thread thread3 = new Thread(t); thread1.setName("窗口1" ); thread2.setName("窗口2" ); thread3.setName("窗口3" ); thread1.start(); thread2.start(); thread3.start(); } }
添加了同步代码块,就不会再出现重票错票的问题
使用同步代码块解决继承Thread类的线程安全问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class ThreadTest1 extends Thread { private static int ticket = 50 ; private static Object obj = new Object(); @Override public void run () { while (true ){ try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj){ if (ticket <= 0 ) break ; System.out.println(Thread.currentThread().getName() + "卖出:" + ticket); ticket--; } } } } public class Synchornized3 { public static void main (String[] args) { ThreadTest1 t1 = new ThreadTest1(); ThreadTest1 t2 = new ThreadTest1(); t1.setName("窗口1" ); t2.setName("窗口2" ); t1.start(); t2.start(); } }
使用同步监视器的注意点
使用同步代码块包含同步代码不能包含少了也不能包含多了
同步监视器除了可以使用任意类的对象,也可以考虑使用 this 和当前类本身,类也是一种对象
同步监视器要始终是唯一的,多个线程共用同一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class WindowTest implements Runnable { private int ticket = 100 ; @Override public void run () { while (true ){ synchronized (WindowTest.class){ if (ticket <= 0 ) break ; System.out.println(Thread.currentThread().getName() + "卖出:" + ticket); ticket--; } } } }
解决安全问题的方法二:使用同步方法解决实现Runnable线程安全问题 如果操作共享受的代码在一个独立的方法中,我们可以将这个方法设置为同步方法。设置的方式是在方法名称前面添加关键字 synchornized
,使之成为一个同步方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class TestClass1 implements Runnable { private int ticket = 100 ; @Override public void run () { while (true ){ try { Thread.sleep(50 ); } catch (InterruptedException e) { e.printStackTrace(); } if (show()) break ; } } public synchronized boolean show () { if (ticket <= 0 ) return true ; System.out.println(Thread.currentThread().getName() + "卖出:" + ticket); ticket--; return false ; } } public class SyncMethod1 { public static void main (String[] args) { TestClass1 testClass1 = new TestClass1(); Thread t1 = new Thread(testClass1); Thread t2 = new Thread(testClass1); t1.setName("窗口1" ); t2.setName("窗口2" ); t1.start(); t2.start(); } }
使用同步方法解决继承Thread类的线程安全问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class TestClass2 extends Thread { private static int ticket = 100 ; @Override public void run () { while (true ){ try { Thread.sleep(50 ); } catch (InterruptedException e) { e.printStackTrace(); } if (show()) break ; } } public static synchronized boolean show () { if (ticket <= 0 ) return true ; System.out.println(Thread.currentThread().getName() + "卖出:" + ticket); ticket--; return false ; } } public class SyncMethod2 { public static void main (String[] args) { TestClass2 t1 = new TestClass2(); TestClass2 t2 = new TestClass2(); t1.setName("窗口1" ); t2.setName("窗口2" ); t1.start(); t2.start(); } }
同步方法的总结
同步方法也有同步监视器,只不过不需要我们显示的声明
非静态的同步方法同步监视器是 this
静态的同步方法同步监视器是:当前类本身 Xxx.class
线程安全的单例模式之懒汉式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Bank { private Bank () {} private static Bank instance = null ; public static Bank getInstance () { if (instance == null ){ synchronized (Bank.class){ if (instance == null ){ instance = new Bank(); } } } return instance; } } public class BankTest { public static void main (String[] args) { Bank b1 = Bank.getInstance(); Bank b2 = Bank.getInstance(); System.out.println(b1 == b2); } }
死锁的问题 死锁的理解:不同的线程分别占用对方需要的同步资源不放弃,都在等在对方放弃自己需要的同步资源,就形成了线程死锁。
出现死锁后,不会出现异常,不会出现提示,只是所有的线程进入阻塞状态,程序不会继续往下执行。在开发中我们要避免死锁的发生
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public class DeadlockTest { public static void main (String[] args) { StringBuffer s1 = new StringBuffer(); StringBuffer s2 = new StringBuffer(); new Thread(){ @Override public void run () { synchronized (s1){ s1.append("a" ); s2.append("1" ); try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (s2){ s1.append("b" ); s2.append("2" ); System.out.println(s1); System.out.println(s2); } } } }.start(); new Thread( new Runnable() { @Override public void run () { synchronized (s2){ s1.append("c" ); s2.append("3" ); try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (s1){ s1.append("d" ); s2.append("4" ); System.out.println(s1); System.out.println(s2); } } } } ).start(); } }
解决安全问题的方法三:使用Lock锁方式解决线程安全问题 实现方式:
1.声明 ReentrantLock 类的实例
2.在需要同步的代码上用这个类实例化出的对象调用 lock() 方法
3.同步代码执行结束后调用 unlock() 方法解锁线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 import java.util.concurrent.locks.ReentrantLock;class Lock1 implements Runnable { private int ticket = 50 ; private ReentrantLock lock = new ReentrantLock(); @Override public void run () { while (true ){ try { lock.lock(); try { Thread.sleep(50 ); } catch (InterruptedException e) { e.printStackTrace(); } if (ticket <= 0 ) break ; System.out.println(Thread.currentThread().getName() + "卖出:" + ticket); ticket--; }finally { lock.unlock(); } } } } public class LockTest { public static void main (String[] args) { Lock1 l1 = new Lock1(); Thread t1 = new Thread(l1); Thread t2 = new Thread(l1); t1.setName("窗口1" ); t2.setName("窗口2" ); t1.start(); t2.start(); } }
synchronized 和 ReentrantLock 的异同 相同点:都是用来解决线程安全问题
不同点:synchronized
执行完响应的同步代码后会自动释放同步监听器。ReentrantLock
类的实例在执行同步代码前需要手动的调用 lock 方法为同步代码上锁,执行完响应的同步代码后需要手动的调用 unlock 方法来解锁
线程安全问题练习题 题目:设置甲乙两个账户往同一个账号中分别存入3000元,各分3次存,每次存1000,每次存完后打印当前账户的余额
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 import java.util.concurrent.locks.ReentrantLock;class Account { public double balance = 0 ; public ReentrantLock lock = new ReentrantLock(); public void setBalance (double balance) { try { lock.lock(); this .balance += balance; try { Thread.sleep(300 ); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + ":存钱成功,账户余额:" + this .balance); }finally { lock.unlock(); } } } class Customer extends Thread { private Account act = null ; public Customer (Account act) { this .act = act; } @Override public void run () { for (int i = 0 ; i < 3 ; i++) { act.setBalance(1000 ); } } } public class AccountTest { public static void main (String[] args) { Account account = new Account(); Customer customer1 = new Customer(account); Customer customer2 = new Customer(account); customer1.setName("甲" ); customer2.setName("乙" ); customer1.start(); customer2.start(); } }
线程的通信 例子:实现两个线程交替从1打印到100
要使用三个方法:
wait()
执行此方法后,线程进入阻塞状态并释放同步监视器
notify()
执行此方法后,就会唤醒被 wait
的方法,如果存在多个线程被wait
,则优先唤醒优先级高的线程
notifyAll()
执行此方法后,会唤醒所有被wait
的线程
使用wait(),notify(),notifyAll()
这三个方法的注意点
只能使用在同步代码块或者同步方法中
这三个方法的调用者必须是同步监视器,否则会报错 IllegalMonitorStateException
这三个方法定义在Object类中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Communication implements Runnable { private int number = 1 ; private Object obj = new Object(); @Override public void run () { while (true ){ synchronized (obj){ obj.notify(); if (number > 100 ) break ; System.out.println(Thread.currentThread().getName() + ":" + number); number++; try { obj.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } public class CommunicatuinTest { public static void main (String[] args) { Communication comm = new Communication(); Thread t1 = new Thread(comm); Thread t2 = new Thread(comm); t1.setName("线程1" ); t2.setName("线程2" ); t1.start(); t2.start(); } }
执行的效果如下
sleep 和 wait 的区别 相同点:
sleep()
和wait()
都可以让线程进入阻塞状态
不同点
定义的地方不同,sleep
定义在Thread
类中,wait
定义在Object
类中
使用范围不同,sleep
可以在任意地方使用,使用后可以让当前线程阻塞指定的时长,wait
只能通过同步监视器来调用,所以只能在同步方法和同步监视器中使用
如果在同一个同步代码块中即使用了sleep
也使用了wait
,那么sleep
执行完毕后不会释放同步监视器,wait
执行完毕后会释放同步监视器
创建多线程方法三:实现Callable接口的方式创建线程 Callable
和Runnable
相比,Callable
的功能更强大
相比 run 方法,Callable
接口需要实现的是 call
方法,并且call
方法有返回值
call
方法可以抛出异常
支持泛型返回值
需要借助FutureTask
类,必须获取线程返回结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;class MyCallable implements Callable { @Override public Object call () throws Exception { int num = 0 ; for (int i = 0 ; i < 50 ; i++) { if (i % 2 == 0 ){ System.out.println(i); num += i; } } return num; } } public class CallableJava { public static void main (String[] args) { MyCallable myCallable = new MyCallable(); FutureTask futureTask = new FutureTask(myCallable); new Thread(futureTask).start(); try { Integer count = (Integer)futureTask.get(); System.out.println(count); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
创建多线程方法四:使用线程池创建多个线程 线程池的好处:
提高响应速度(减少了创建新线程的时间)
减低资源的消耗(重复利用线程池中的线程,不需要每次都创建)
便于管理线程,需要使用 ThreadPoolExecutor
类来强转ExecutorService
类的实例对象,然后使用ThreadPoolExecutor
类的实例来调用下面的方法
setCorePoolSize
设置线程池的数量
setMaximumPoolSize
设置最大线程数量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 import java.util.concurrent.*;class RunTest 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 CallTest implements Callable { @Override public Object call () throws Exception { Integer num = 0 ; for (int i = 0 ; i < 100 ; i++) { if (i % 2 != 0 ) { System.out.println(Thread.currentThread().getName() + ":" + i); num += i; } } return num; } } public class PoolJava { public static void main (String[] args) { ExecutorService service = Executors.newFixedThreadPool(5 ); System.out.println(service.getClass()); ThreadPoolExecutor service1 = (ThreadPoolExecutor)service; service1.setCorePoolSize(10 ); System.out.println(service1.getCorePoolSize()); service.execute(new RunTest()); Future future = service.submit(new CallTest()); try { Integer obj = (Integer)future.get(); System.out.println(obj); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } service.shutdown(); } }