A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© mvplee 中级黑马   /  2013-6-19 10:45  /  1664 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

面试都过了,就是技术分不够,郁闷了,现在分享我的学习笔记,以及一些电子书,赚点技术分。希望版主高抬贵手。


多线程概述:
单线程如同一个餐厅只雇用一个服务员,服务员必须做完一件事情后才能做下一件事情。多线程如同一个餐厅雇佣很多名服务员,他们可以同时做很多事情,并且相互之间不会干扰。
       一个程序被加载进内存运行时,就是一个进程,多线程使同一个进程可以并发处理多个任务,线程是进程的执行单元。一个进程可以拥有多个进程,一个线程必须有一个父进程。
       每个线程拥有自己的堆栈,自己的程序计数器和自己的局部变量,但不拥有系统资源,多个线程共享父进程所拥有的全部资源。线程的执行时抢占式的,当前的线程在任何时候都可能被挂起,以便CUP运行另外的线程。
       一个程序运行后至少有一个进程,一个进程可以包含多个程序,但至少包含一个线程。

线程的创建和启动:方法1创建线程需要继承Thread类,并重写run()run()代表线程需要完成的任务,run()是线程的执行体,启动线程通过start()
  1. public class FirstThread extends Thread{
  2.         private int i;
  3.         @Override
  4.         public void run(){
  5.                 for (; i < 100; i++) {
  6.                         System.out.println(this.getName()+"\t"+i);
  7.                 }
  8.         }
  9.         public static void main(String[] args) {
  10.                 for (int i = 0; i < 100; i++) {
  11.                         System.out.println(Thread.currentThread().getName()+" "+i);
  12.                         if(i==20){
  13.                                 new FirstThread().start();
  14.                                 new FirstThread().start();
  15.                         }
  16.                 }
  17.         }
  18. }
复制代码
main()中当循环变量i=20时,启动两个线程。属性i在两个线程中的打印结果是不连续的,证明了多线程之间运行互不干扰,因为new了两个线程对象。以上程序启动时有3个线程,main()也是一个线程,成为主线程。
方法2实现Runnable接口并实现run()fun()方法内是线程的执行体。
  1. public class SecondThread implements Runnable {
  2.         private int i;
  3.         @Override
  4.         public void run() {
  5.                 for (; i < 100; i++) {
  6.                         System.out.println(Thread.currentThread().getName() + "\t" + i);
  7.                 }
  8.         }
  9.         public static void main(String[] args) {
  10.                         SecondThread st = new SecondThread();
  11.                         for (int i = 0; i < 100; i++) {
  12.                                 System.out.println(Thread.currentThread().getName()+" "+i);
  13.                                 if(i==20){
  14.                                         new Thread(st,"线程-1").start();
  15.                                         new Thread(st,"线程-2").start();
  16.                                 }
  17.                         }
  18.         }
  19. }
复制代码
通过实现Runnable接口在启动多线程时也需要使用Thread类并调用start()。这种方式创建的多个线程可以共享线程类中的属性,因为只创建一个Runnable接口的子类对象,这一个对象被Thread类引用。
方法3通过实现Callable接口,并且实现call()
  1. ublic class ThirdThread implements Callable<Integer> {
  2.         @Override
  3.         public Integer call() throws Exception {
  4.                 int i=0;
  5.                 for (; i <100; i++) {                        System.out.println(Thread.currentThread().getName()+"\t"+i);
  6.                 }
  7.                 return i;
  8.         }
  9.         public static void main(String[] args) throws Exception {
  10.                 ThirdThread tt = new ThirdThread();
  11.                  FutureTask<Integer> task = new FutureTask<Integer>(tt);
  12.                  for(int i=0;i<100;i++){
  13.                          System.out.println(Thread.currentThread().getName());
  14.                          if(i==20){
  15.                                  new Thread(task,"有返回值的线程").start();
  16.                          }
  17.                  }
  18.                  System.out.println(task.get());
  19.         }
  20. }
复制代码
call()可以作为线程的执行体,call()run()强大,可以有返回值,可以抛异常,Java5新增的接口。

线程的生命周期:
新建(New)à就绪(Runable)à运行(Running)à阻塞(Blocked)à死亡(Dead)


线程控制:join():调用线程将被阻塞,直到被join()加入的线程执行完为止。
  1. public class JoinThread extends Thread{
  2.                 public JoinThread(String name) {
  3.                 super(name);
  4.         }
  5.         @Override
  6.         public void run(){
  7.                 for(int i=0;i<100;i++){
  8.                         System.out.println(this.getName()+"\t"+i);
  9.                 }
  10.         }
  11.         public static void main(String[] args) throws Exception {
  12.                 new JoinThread("新线程").start();
  13.                 for(int i=0;i<100;i++){
  14.                         if(i==20){
  15.                                 JoinThread jt = new JoinThread("被Join的线程");
  16.                                 jt.start();
  17.                                 jt.join();
  18.                         }
  19.                 System.out.println(Thread.currentThread().getName()+"\t"+i);
  20.                 }                       
  21.         }
  22. }
复制代码
main线程调用了jt线程的join()mian线程必须等jt线程执行结束后才会继续执行。
setDaemon()后台线程,如果所有前台线程都死亡,JVM会通知后台线程死亡,main线程默认是后台线程,设置一个线程为后台线程,必须在线程start()前设置。
  1. public class DaemonThread extends Thread {
  2.         @Override
  3.         public void run() {
  4.                 for (int i = 0; i < 1000; i++) {
  5.                         System.out.println(this.getName() + "\t" + i);
  6.                 }
  7.         }
  8.         public static void main(String[] args) {
  9.                 DaemonThread dt = new DaemonThread();
  10.                 dt.setDaemon(true);// 设置线程为后台线程
  11.                 dt.start();
  12.                 for (int i = 0; i < 10; i++) {
  13.                         System.out.println(Thread.currentThread().getName() + " " + i);
  14.                 }
  15.                 // 程序运行到此处,前台线程(main线程)结束,后台dt线程也随之结束
  16.         }
  17. }
复制代码
sleep()线程休眠,并进入阻塞状态。
  1. public class SleepThread {
  2.         public static void main(String[] args) throws Exception {
  3.                 for (int i = 0; i < 10; i++) {
  4.                         System.out.println("Current time : "+new Date());
  5.                         Thread.sleep(1000);
  6.                 }
  7.         }
  8. }
复制代码
线程休眠后进入阻塞状态,并且不会获得CPU执行资格。
yield()让当前正在执行的线程暂停,但不会阻塞该线程,只是将线程转入就绪状态,暂停后只有优先级与当前线程相同,或者更高的处于就绪状态的线程财货获得CPU的执行资格。
  1. public class YieldTest extends Thread {
  2.         private String name;
  3.         public YieldTest(String name) {
  4.                 super(name);
  5.         }
  6.         @Override
  7.         public void run() {
  8.                 for (int i = 0; i < 50; i++) {
  9.                         System.out.println(this.getName() + "\t" + i);
  10.                         if (i == 20)
  11.                                 Thread.yield();
  12.                 }
  13.         }
  14.         public static void main(String[] args) {
  15.                 YieldTest y1 = new YieldTest("优先级高");
  16.                 y1.setPriority(Thread.MAX_PRIORITY);
  17.                 YieldTest y2 = new YieldTest("优先级低");
  18.                 y2.setPriority(Thread.MIN_PRIORITY);
  19.                 y1.start();
  20.                 y2.start();
  21.         }
  22. }
复制代码





评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

3 个回复

倒序浏览
改变线程优先级:MAX_PRIOPERTY=10MIN_PRIOPERTY=0NORM_PRIOPERTY=5,由于修改优先级需要操作系统底层的支持,Java虽然提供了10个等级的优先级,但还是建议使用常量的方法配置优先级。
sleep()yield()区别:
1、  sleep()暂停后,会给其它线程执行资格,不会考虑优先级,yield()只会给优先级相同或
更高的线程执行资格。
2、sleep()会暂停当前线程,并且进入阻塞状态,yield()不会,只是强制让线程进入就绪状态,一个线程可能调用yield()后,又立即获得了CPU的执行资格。
3、sleep()抛InterruptedException(),yield()没有异常。


线程同步:当使用多个线程访问同一个数据时就有可能出现线程安全问题。例如,银行取钱:定义账户类:
  1. public class Account {
  2.         private Account account;//模拟账户
  3.         private double drawAmount;//取出的钱       
  4. public Account() {
  5.                 super();
  6.         }
  7.         public Account(String accountNo, double balance) {
  8.                 super();
  9.                 this.accountNo = accountNo;
  10.                 this.balance = balance;
  11.         }
  12.         @Override
  13.         public int hashCode() {
  14.                 return accountNo.hashCode();
  15.         }
  16.         @Override
  17.         public boolean equals(Object obj) {
  18.                 if (obj == null || obj.getClass() != Account.class)
  19.                         return false;
  20.                 if (this == obj)
  21.                         return true;
  22.                 Account a = (Account) obj;
  23.                 if (this.accountNo.equals(a.accountNo) && this.balance == a.balance)
  24.                         return true;
  25.                 return true;
  26.         }
  27.         public String getAccountNo() {
  28.                 return accountNo;
  29.         }
  30.         public void setAccountNo(String accountNo) {
  31.                 this.accountNo = accountNo;
  32.         }
  33.         public double getBalance() {
  34.                 return balance;
  35.         }
  36.         public void setBalance(double balance) {
  37.                 this.balance = balance;
  38.         }
  39. }
复制代码
创建取钱的线程类:实现简单的取钱逻辑,判断账户余额
  1. public class DrawThread extends Thread {
  2.         private Account account;
  3.         private double drawAmount;
  4.         public DrawThread(String name, Account account, double drawAmount) {
  5.                 super(name);
  6.                 this.account = account;
  7.                 this.drawAmount = drawAmount;
  8.         }
  9.         @Override
  10.         public void run() {
  11.                 // 账户里有余额
  12.                 if (account.getBalance() >= this.drawAmount) {
  13.                         System.out.println(this.getName() + "__取钱成功,吐出钞票:" + drawAmount);
  14.                         account.setBalance(account.getBalance() - drawAmount);// 修改账户余额
  15.                         System.out.println("余额:" + account.getBalance());
  16.                 } else {
  17.                         // 账户余额不足
  18.                         System.out.println(this.getName() + "__取钱失败,余额不足!");
  19.                 }
  20.         }
  21. }
复制代码
测试:
  1. public class DrawTest {
  2.         public static void main(String[] args) {
  3.                 Account acct = new Account();
  4.                 acct.setBalance(1000);
  5.                 new DrawThread("甲",acct,800).start();
  6.                 new DrawThread("乙",acct,800).start();
  7.         }
  8. }
  9. 输出结果:
  10. 乙__取钱成功,吐出钞票:800.0
  11. 甲__取钱成功,吐出钞票:800.0
  12. 余额:200.0
  13. 余额:-600.0
复制代码
账户里只有1000K,却取出了1600K,多线程操作同一资源时出现了线程安全。原因时run()不具备安全性,程序中两个线程并发的修改了Account对象,这就问题。
Java中为了解决线程安全问题,加入了同步监视器,任何时刻只能有一个线程可以获得同步监视器的锁,当同步代码执行完后,该线程将会释放对该同步监视器的锁给其它线程使用。
修改run()加入同步代码块:
  1.         @Override
  2.         public void run() {
  3.                 synchronized (account) {
  4.                         // 账户里有余额
  5.                         if (account.getBalance() >= this.drawAmount) {
  6.                                 System.out
  7.                                                 .println(this.getName() + "__取钱成功,吐出钞票:" + drawAmount);
  8.                                 account.setBalance(account.getBalance() - drawAmount);// 修改账户余额
  9.                                 System.out.println("余额:" + account.getBalance());
  10.                         } else {
  11.                                 // 账户余额不足
  12.                                 System.out.println(this.getName() + "__取钱失败,余额不足!");
  13.                         }
  14.                 }
  15.         }
  16. 甲__取钱成功,吐出钞票:800.0
  17. 余额:200.0
  18. 乙__取钱失败,余额不足!
复制代码
synchronized中需要传入一个需要同步的监视器对象,使用account作为同步的监视器对象,同步后,在操作Account对象时逻辑为:“加锁à操作à释放锁”。任何线程在操作共享资源时首先要加锁,加锁期间其它线程无法修改共享资源,修改完成后释放共享资源的锁。通过这种方法保证并发线程访问、修改共享资源时只能有一个线程对其操作。
使用同步方法:在Account类中添加一个取钱的方法:
  1.         public synchronized void draw(double drawAmount) {
  2.                 // 账户里有余额
  3.                 if (getBalance() >= drawAmount) {
  4.                         System.out.println(Thread.currentThread().getName()
  5.                                         + "__取钱成功,吐出钞票:" + drawAmount);
  6.                         balance -= drawAmount;// 修改账户余额
  7.                         System.out.println("余额:" + balance);
  8.                 } else {
  9.                         // 账户余额不足
  10.                         System.out.println(Thread.currentThread().getName()
  11.                                         + "__取钱失败,余额不足!");
  12.                 }
  13.         }
复制代码
synchronized关键字修饰方法时,方法就变成同步方法了,同步方法使用的对象监视器是this,调用该方法的对象。sleep()yield()suspend()不会释放监视器的锁。
Java1.5可以通过显示定义同步锁的方式来为共享资源加锁,使用Lock对象,每次只能有一个线程对Lock对象加锁。代码格式如下:
  1. public class X {
  2.         private final Lock lock = new ReentrantLock();
  3.         public void m() {
  4.                 lock.lock();
  5.                 try {

  6.                 } catch (Exception e) {
  7.                        
  8.                 } finally {
  9.                         lock.unlock();
  10.                 }
  11.         }
  12. }
复制代码
使用finally块保证锁一定会被释放。修改Account类,使用Lock对象为draw()加锁:
  1. public class Account {
  2.         private String accountNo;
  3.         private double balance;
  4.         private Lock lock = new ReentrantLock();
  5.         public Account() {
  6.                 super();
  7.         }
  8.         public Account(String accountNo, double balance) {
  9.                 super();
  10.                 this.accountNo = accountNo;
  11.                 this.balance = balance;
  12.         }
  13.         public void draw(double drawAmount) {
  14.                 lock.lock();// 显示加锁
  15.                 try {
  16.                         // 账户里有余额
  17.                         if (balance >= drawAmount) {
  18.                                 System.out.println(Thread.currentThread().getName()
  19.                                                 + "__取钱成功,吐出钞票:" + drawAmount);
  20.                                 balance -= drawAmount;// 修改账户余额
  21.                                 System.out.println("余额:" + balance);
  22.                         } else {
  23.                                 // 账户余额不足
  24.                                 System.out.println(Thread.currentThread().getName()
  25.                                                 + "__取钱失败,余额不足!");
  26.                         }
  27.                 } catch (Exception e) {
  28.                         e.printStackTrace();
  29.                 } finally {
  30.                         lock.unlock();// 显示释放锁
  31.                 }
  32.         }
  33.         @Override
  34.         public int hashCode() {
  35.                 return accountNo.hashCode();
  36.         }
  37.         @Override
  38.         public boolean equals(Object obj) {
  39.                 if (obj == null || obj.getClass() != Account.class)
  40.                         return false;
  41.                 if (this == obj)
  42.                         return true;
  43.                 Account a = (Account) obj;
  44.                 if (this.accountNo.equals(a.accountNo) && this.balance == a.balance)
  45.                         return true;
  46.                 return true;
  47.         }
  48.         public String getAccountNo() {
  49.                 return accountNo;
  50.         }
  51.         public void setAccountNo(String accountNo) {
  52.                 this.accountNo = accountNo;
  53.         }
  54.         public double getBalance() {
  55.                 return balance;
  56.         }
  57.         public void setBalance(double balance) {
  58.                 this.balance = balance;
  59.         }
  60. }
复制代码







评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

回复 使用道具 举报
一个线程可以对已经被加锁的ReentrantLock锁再次加锁,ReentrantLock对象维持一个计数器来追踪lock()方法的嵌套调用。
当两个线程相互等待对象释放同步监视器时就会发生死锁。
死锁实例1
  1. public class A {
  2.         public synchronized void A2B(B b) {
  3.                 System.out.println("当前线程:" + Thread.currentThread().getName()
  4.                                 + "进入method() in class A");
  5.                 try {
  6.                         Thread.sleep(2000);
  7.                 } catch (Exception e) {
  8.                         e.printStackTrace();
  9.                 }
  10.                 System.out.println("当前线程:" + Thread.currentThread().getName()
  11.                                 + "准备进入method() in class B");
  12.                 b.method();
  13.         }
  14.         public void mehod() {
  15.                 System.out.println("method() in class A");
  16.         }
  17. }
  18. public class B {
  19.         public synchronized void B2A(A a) {
  20.                 System.out.println("当前线程:" + Thread.currentThread().getName()
  21.                                 + "进入method() in class B");
  22.                 try {
  23.                         Thread.sleep(2000);
  24.                 } catch (Exception e) {
  25.                         e.printStackTrace();
  26.                 }
  27.                 System.out.println("当前线程:" + Thread.currentThread().getName()
  28.                                 + "准备进入method() in class A");
  29.                 a.mehod();
  30.         }
  31.         public void method() {
  32.                 System.out.println("method() in class B");
  33.         }
  34. }
  35. public class DeadLock implements Runnable {
  36.         A a = new A();
  37.         B b = new B();
  38.         public void init() {
  39.                 Thread.currentThread().setName("主线程");
  40.                 a.A2B(b);
  41.                 System.out.println("进入主线程之后");
  42.         }
  43.         @Override
  44.         public void run() {
  45.                 Thread.currentThread().setName("副线程");
  46.                 b.B2A(a);
  47.                 System.out.println("进入副线程之后");
  48.         }
  49.         public static void main(String[] args) {
  50.                 DeadLock dead = new DeadLock();
  51.                 new Thread(dead).start();
  52.                 dead.init();
  53.         }
  54. }
复制代码
死多实例2
  1. class Test implements Runnable {
  2.         private boolean flag;
  3.         public Test(boolean flag) {
  4.                 this.flag = flag;
  5.         }
  6.         @Override
  7.         public void run() {
  8.                 if (flag) {
  9.                         synchronized (MyLock.locka) {
  10.                                 System.out.println("if locka");
  11.                                 synchronized (MyLock.lockb) {
  12.                                         System.out.println("if lockb");
  13.                                 }
  14.                         }
  15.                 } else {
  16.                         synchronized (MyLock.locka) {
  17.                                 System.out.println("if lockb");
  18.                                 synchronized (MyLock.lockb) {
  19.                                         System.out.println("if locka");
  20.                                 }
  21.                         }
  22.                 }
  23.         }
  24. }
  25. class MyLock {
  26.         public static Object locka = new Object();
  27.         public static Object lockb = new Object();
  28. }
  29. /**
  30. * 多线程的死锁
  31. * @author RockLee
  32. *
  33. */
  34. public class DeadLockDemo {
  35.         public static void main(String[] args) {
  36.                 Test t1 = new Test(true);
  37.                 Test t2 = new Test(false);
  38.                 new Thread(t1).start();
  39.                 new Thread(t2).start();
  40.         }
  41. }
复制代码
线程间通信:
Object类中有三个方法用于实现线程间通信,wait()notify()notifyAll(),这三个方法必须有同步锁的监视器对象调用,synchronized方法使用this调用,synchronized块使用同步监视器对象调用。
wait():当前调用线程等待,直到其它线程使用同步监视器对象调用notify()notifyAll()后才能唤醒。
notify():唤醒当前同步锁上的单个线程。
notifyAll():唤醒等待当前同步锁上的所有线程。
使用两个线程模拟存钱者和取钱者,不断重复存/取操作,但要求必须存一次,取一次。
定义Account账户类:
  1. public class Account {
  2.         private String accountNo;// 账户编号
  3.         private double balace;// 帐户余额
  4.         private boolean flag = false;// 定义存/取钱标记位
  5.         public Account(String accountNo, double balace) {
  6.                 super();
  7.                 this.accountNo = accountNo;
  8.                 this.balace = balace;
  9.         }
  10.         /**
  11.          * 定义存钱方法,flag=true时,表示已经存过钱了,账户里有钱,线程等待
  12.          *
  13.          * @param drawAmount
  14.          */
  15.         public synchronized void deposit(double depositAmount) {
  16.                 if (flag) {
  17.                         try {
  18.                                 this.wait();
  19.                         } catch (InterruptedException e) {
  20.                                 e.printStackTrace();
  21.                         }
  22.                 } else {
  23.                         System.out.println(Thread.currentThread().getName() + "存款:"
  24.                                         + depositAmount);
  25.                         balace += depositAmount;
  26.                         System.out.println("账户余额:" + balace);
  27.                         flag = true;// 存入钱后改变标记位
  28.                         this.notifyAll();// 唤醒等待线程
  29.                 }
  30.         }
  31.         /**
  32.          * 取钱方法,flag=false时,表示已经取过钱了,等待
  33.          *
  34.          * @param drawAmount
  35.          */
  36.         public synchronized void draw(double drawAmount) {
  37.                 if (!flag) {
  38.                         try {
  39.                                 this.wait();
  40.                         } catch (InterruptedException e) {
  41.                                 e.printStackTrace();
  42.                         }
  43.                 } else {
  44.                         System.out.println(Thread.currentThread().getName() + "取钱:"
  45.                                         + drawAmount);
  46.                         balace -= drawAmount;
  47.                         System.out.println("账户余额:" + balace);
  48.                         flag = false;
  49.                         this.notifyAll();
  50.                 }
  51.         }
  52.         public String getAccountNo() {
  53.                 return accountNo;
  54.         }
  55.         public void setAccountNo(String accountNo) {
  56.                 this.accountNo = accountNo;
  57.         }
  58.         public double getBalace() {
  59.                 return balace;
  60.         }
  61. }
复制代码
定义一个线程模拟取钱100次:
  1. public class DrawThread extends Thread {
  2.         private Account account;
  3.         private double drawAmount;
  4.         public DrawThread(String name,Account account, double drawAmount) {
  5.                 super(name);
  6.                 this.account = account;
  7.                 this.drawAmount = drawAmount;
  8.         }
  9.         @Override
  10.         public void run() {
  11.                 // 模拟取钱100次
  12.                 for (int i = 0; i < 100; i++) {
  13.                         account.draw(drawAmount);
  14.                 }
  15.         }
  16. }
复制代码
定义一个线程模拟存钱100次:
  1. public class DepositThread extends Thread {
  2.         private Account account;
  3.         private double depositAmount;
  4.         public DepositThread(String name, Account account, double depositAmount) {
  5.                 super(name);
  6.                 this.account = account;
  7.                 this.depositAmount = depositAmount;
  8.         }
  9.         @Override
  10.         public void run() {
  11.                 // 模拟存钱100次
  12.                 for (int i = 0; i < 100; i++) {
  13.                         account.deposit(depositAmount);
  14.                 }
  15.         }
  16. }
复制代码
测试:
  1. public class DrwaTest {
  2.         public static void main(String[] args) {
  3.                 Account account = new Account("110", 0);
  4.                 new DrawThread("取钱", account, 800).start();
  5.                 new DepositThread("存钱甲", account, 800).start();
  6.         }
  7. }
  8. 存钱甲存款:800.0
  9. 账户余额:800.0
  10. 取钱取钱:800.0
  11. 账户余额:0.0
复制代码
线程池:
系统启动一个线程的成本比较高,尤其需要创建大量生存周期短暂的线程时,就不得不考虑性能,使用线程池可以很好的提高性能。线程池在系统创建启动时即创建了大量空闲线程,程序将线程运行的对象传给线程池,线程池会启动一个线程来执行run(),当run()结束后线程池中的线程不会死亡,将再次返回线程池成为空闲状态,等待执行下一个线程运行的对象。
创建线程池:
1、  Excutors工厂类创建ExecutorService对象,ExecutorService代表线程池类对象;
2、  创建线程类对象
3、     ExecutorService调用submit()执行线程类run();
  1. public class ThreadPoolTest {
  2.         public static void main(String[] args) {
  3.                 ExecutorService pool = Executors.newFixedThreadPool(6);// 创建线程池对象,池中有6个线程
  4.                 // 创建并通过线程池启动一个线程
  5.                 pool.submit(new Runnable() {
  6.                         @Override
  7.                         public void run() {
  8.                                 for (int i = 0; i < 100; i++) {                                        System.out.println(Thread.currentThread().getName()
  9.                                                         + "--->" + i);
  10.                                 }
  11.                         }
  12.                 });
  13.                 // 创建并通过线程池启动一个线程
  14.                 pool.submit(new Runnable() {
  15.                         @Override
  16.                         public void run() {
  17.                                 for (int i = 0; i < 100; i++) {                                        System.out.println(Thread.currentThread().getName()
  18.                                                         + "--->" + i);
  19.                                 }
  20.                         }
  21.                 });
  22.                 pool.shutdown();// 关闭线程池
  23.         }
  24. }
复制代码
版主,小手一抖
俺的技术分到手







评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1 很给力!

查看全部评分

回复 使用道具 举报
哥们,不错{:soso_e179:}
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马