java多线程
一:买票的案例:通过Thread 和Runale实现多线程
//通过Thread实现 package mypack; class Ticket extends Thread{ private static int ticket=100; public void run() { // TODO Auto-generated method stub while(true){ if(ticket>0){ System.out.println(Thread.currentThread().getName()+"...sale..."+ticket--); }else{ break; } } } } public class TicketDemo { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Ticket t1 = new Ticket(); Ticket t2 = new Ticket(); t1.start(); t2.start(); } } //通过继承Runnable实现 package mypack; class Ticket implements Runnable{ private int ticket = 100; public void run() { // TODO Auto-generated method stub while(true){ if(ticket>0){ try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"...sale..."+ticket--); }else{ break; } } } } public class TicketDemo2 { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t1.start(); t2.start(); } } //上面两种方法功能一样,不过Thread
二:多线程异常
package mypack;
class Ticket extends Thread{
private static int ticket=100;
public void run() {
// TODO Auto-generated method stub
while(true){
if(ticket>0){
try {
Thread.sleep(100); //睡眠,转让执行权
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"...sale..."+ticket--);
}else{
break;
}
}
}
}
public class TicketDemo {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Ticket t1 = new Ticket();
Ticket t2 = new Ticket();
t1.start();
t2.start();
}
}
//上面就是让线程睡眠,然后在苏醒时候,别的进程已经改变了原变量的内容
多线程运行安全问题:
问题原因:
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完,另一个线程参与进来执行,导致共享数据的错误.
解决办法;对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行.
解决多线程问题
synchronize(对象){
}
通过同步代码块解决线程安全问题
解决多线程问题:
1,明确那些代码是多线程运行代码.
2,明确共享数据.
3,明确多线程运行代码中那些语句是操作共享数据.
package mypack; class Ticket extends Thread { Object obj = new Object();//创建上帝对象 private static int ticket = 100; public void run() { // TODO Auto-generated method stub while (true) { synchronized (obj) { if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "...sale..." + ticket--); } else { break; } } } } } public class TicketDemo { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Ticket t1 = new Ticket(); Ticket t2 = new Ticket(); t1.start(); t2.start(); } }
通过同步函数解决安全问题
package mypack;
class Bank {
private int sum;
Object obj = new Object();
// 同步函数
public synchronized void add(int n) {
sum = sum + n;
System.out.println("sum = " + sum);
}
}
class Cus implements Runnable {
private Bank b = new Bank();
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 3; i++) {
b.add(100);
}
}
}
public class BankDemo {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Cus c = new Cus();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start(); //每个线程和每个线程的run方法是分开的,run方法是独立运行的,
t2.start();
}
}
同步函数用的锁是那一个?
函数需要被对象调用,那么函数都有一个所属对象引用,就是this.
所以同步函数使用的锁是shis.
同步函数和同步代码块共同操作共享数据
package mypack;
class Ticket implements Runnable {
private int ticket = 100;
Object obj = new Object();
boolean flag = true;
public void run() {
// TODO Auto-generated method stub
if (flag) {
while (true) {
synchronized (this) { //这里要确保操作共享数据使用的synchronized 对象是一样
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName()
+ "...code..." + ticket--);
} else {
return;
}
}
}
} else {
while (true) {
show();
}
}
}
public synchronized void show() {
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + "...show..."
+ ticket--);
} else {
return;
}
}
}
public class TicketDemo2 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Ticket t = new Ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
//当启动main函数时候,相当于有3个线程,t1,t2,main t1.start()时候 可能拥有执行权但是还没有执行,一闪而过,t.flag=false执行完了,
//所以要睡眠一下
try{Thread.sleep(10);}catch(Exception e){};
t.flag = false;
t2.start();
}
}
静态同步函数的锁是Class
package mypack;
/**
* 静态进内存,内存中没有本类对象,但是一定有该类对相应的字节码文件对象
* 类名.class 该对象的类型是class
*
* 静态的同步方法,使用的锁是该方法所在类的字节码文件对象. 类名.class
*/
class Ticket implements Runnable {
//由于静态synchronized里面调用ticket,所以ticket要设置成静态
private static int ticket = 100;
Object obj = new Object();
boolean flag = true;
public void run() {
// TODO Auto-generated method stub
if (flag) {
while (true) {
synchronized (Ticket.class) { //这里要确保操作共享数据使用的synchronized 对象是一样
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName()
+ "...code..." + ticket--);
} else {
return;
}
}
}
} else {
while (true) {
show();
}
}
}
public static synchronized void show() {
if (ticket > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
System.out.println(Thread.currentThread().getName() + "...show..."
+ ticket--);
} else {
return;
}
}
}
public class TicketDemo2 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Ticket t = new Ticket();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.start();
//当启动main函数时候,相当于有3个线程,t1,t2,main t1.start()时候 可能拥有执行权但是还没有执行,一闪而过,t.flag=false执行完了,
//所以要睡眠一下
try{Thread.sleep(10);}catch(Exception e){};
t.flag = false;
t2.start();
}
}
懒汉式上锁的应用
class lanhanshi{
private lanhanshi(){}
private static lanhanshi instance;
//如果锁放在这里的话,每次都要去判断,比较低效
public static synchronized lanhanshi getSingleInstance(){
if(instance == null){ //如果在多线程中这里可能线程挂住,A挂住,B进来把下面执行,A又执行
//要保证对象的唯一性,加锁.
instance = new lanhanshi();
}
return instance;
}
}
class ehanshi{
//注意这里要用final修饰,变成常量,不可修改,
private static final ehanshi instance = new ehanshi();
private ehanshi(){}
public ehanshi getSingleInstance(){
return instance;
}
}
优化懒汉式锁
class lanhanshi {
private lanhanshi() {
}
private static lanhanshi instance;
// 如果锁放在这里的话,每次都要去判断,比较低效
public static lanhanshi getSingleInstance() {
if (instance == null) {
synchronized (lanhanshi.class) {
if (instance == null) { // 如果在多线程中这里可能线程挂住,A挂住,B进来把下面执行,A又执行
// 要保证对象的唯一性,加锁.
instance = new lanhanshi();
}
}
}
return instance;
}
}
懒汉式和饿汉式的差别,懒汉式是延迟加载,懒汉式有问题吗? 有.多线程访问时会出现安全问题,可以加同步,用同步代码块,和同步函数都可以,有些低效,用双重判断可以解决效率问题
package mypack;
class Tick implements Runnable {
int ticket = 100;
public void run() {
// TODO Auto-generated method stub
while (true) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "...A..."
+ ticket--);
}
}
}
}
public class Test2 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//这2个tick操作的是不同的对象,ticket 不是共享
Tick tick1 = new Tick();
Tick tick2 = new Tick();
Thread t1 = new Thread(tick1);
Thread t2 = new Thread(tick2);
t1.start();
t2.start();
}
}
写一个死锁程序
package mypack;
class Test implements Runnable{
private boolean flag;
Test(boolean flag){
this.flag = flag;
}
public void run() {
// TODO Auto-generated method stub
if(flag){
synchronized (MyLock.locka) {
System.out.println("if locka");
synchronized (MyLock.lockb) {
System.out.println("if lockb");
}
}
}else{
synchronized (MyLock.lockb) {
System.out.println("else lockb");
synchronized (MyLock.locka) {
System.out.println("else locka");
}
}
}
}
}
//线程运行时候用的锁
class MyLock{
static Object locka = new Object();
static Object lockb = new Object();
}
public class DeadLockDemo {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Test test1 = new Test(true);
Test test2 = new Test(false);
Thread t1 = new Thread(test1);
Thread t2 = new Thread(test2);
t1.start();
t2.start();
}
}
解决多线程安全问题事例
package pack;
/**
* @Description TODO
* @author WiKi
* @date 2014-11-30 上午8:20:38
*/
class Input implements Runnable {
Res r;
Input(Res r) {
this.r = r;
}
public void run() {
// TODO Auto-generated method stub
int x = 0;
while (true) {
synchronized (r) {
if (x == 0) {
r.name = "男人";
r.sex = "boy";
} else {
r.name = "女人";
r.sex = "girl";
}
x = (x + 1) % 2;
}
}
}
}
class Output implements Runnable {
Res r;
Output(Res r) {
this.r = r;
}
public void run() {
// TODO Auto-generated method stub
while (true) {
synchronized (r) {
System.out.println(r.name + "::" + r.sex);
}
}
}
}
class Res {
String name;
String sex;
}
public class Demo {
public static void main(String[] args) {
Res r = new Res();
Input input = new Input(r);
Output output = new Output(r);
Thread t1 = new Thread(input);
Thread t2 = new Thread(output);
t1.start();
t2.start();
}
}
等待唤醒机制
只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒.
package pack;
/**
* @Description TODO
* @author WiKi
* @date 2014-11-30 上午8:20:38
*/
class Input implements Runnable {
Res r;
Input(Res r) {
this.r = r;
}
public void run() {
// TODO Auto-generated method stub
int x = 0;
while (true) {
synchronized (r) {
if(r.flag)
try {
r.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (x == 0) {
r.name = "男人";
r.sex = "boy";
} else {
r.name = "女人";
r.sex = "girl";
}
x = (x + 1) % 2;
r.flag = true;
r.notify();
}
}
}
}
class Output implements Runnable {
Res r;
Output(Res r) {
this.r = r;
}
public void run() {
// TODO Auto-generated method stub
while (true) {
synchronized (r) {
if(!r.flag)
try {
r.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(r.name + "::" + r.sex);
r.flag = false;
r.notify();
}
}
}
}
class Res {
String name;
String sex;
boolean flag;
}
public class Demo {
public static void main(String[] args) {
Res r = new Res();
Input input = new Input(r);
Output output = new Output(r);
Thread t1 = new Thread(input);
Thread t2 = new Thread(output);
t1.start();
t2.start();
}
}
只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒.
等待唤醒机制代码优化
package pack;
/**
* @Description TODO
* @author WiKi
* @date 2014-11-30 上午8:20:38
*/
class Input implements Runnable {
Res r;
Input(Res r) {
this.r = r;
}
public void run() {
// TODO Auto-generated method stub
int x = 0;
while (true) {
if (x == 0) {
r.set("男人", "man");
} else {
r.set("女人", "girl");
}
x = (x + 1) % 2;
}
}
}
class Output implements Runnable {
Res r;
Output(Res r) {
this.r = r;
}
public void run() {
// TODO Auto-generated method stub
while (true) {
r.get();
}
}
}
class Res {
String name;
String sex;
boolean flag;
public synchronized void set(String name, String sex) {
if (flag)
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
this.name = name;
this.sex = sex;
flag = true;
this.notify();
}
public synchronized void get() {
if (!flag)
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + "::" + sex);
flag = false;
this.notify();
}
}
public class Demo {
public static void main(String[] args) {
Res r = new Res();
Input input = new Input(r);
Output output = new Output(r);
Thread t1 = new Thread(input);
Thread t2 = new Thread(output);
t1.start();
t2.start();
}
}
notifyAll while修饰
package pack; class Resource{ private String name; private int count = 1; private boolean flag = false; public synchronized void set(String name){ if(flag) //加了while会造成程序死掉 try{this.wait();}catch(Exception e){}; this.name = name+count++; System.out.println(Thread.currentThread().getName()+"...生产者"+this.name); flag = true; this.notifyAll(); //普通的notify可能唤醒本方线程,没唤醒对方线程.唤醒了本方while修饰的直接死掉 } public synchronized void out(){ if(!flag) try{this.wait();}catch(Exception e){}; System.out.println(Thread.currentThread().getName()+"...消费者..."+name); flag = false; this.notifyAll(); } } class Producer implements Runnable{ Resource res; Producer(Resource res){ this.res = res; } public void run() { // TODO Auto-generated method stub while(true) res.set("+商品+"); } } class Consumer implements Runnable{ Resource res; Consumer(Resource res){ this.res = res; } public void run() { // TODO Auto-generated method stub while(true) res.out(); } } public class Demo { public static void main(String[] args) { Resource res = new Resource(); Producer p = new Producer(res); Consumer c = new Consumer(res); Thread t1 = new Thread(p); Thread t2 = new Thread(p); Thread t3 = new Thread(c); Thread t4 = new Thread(c); t1.start(); t2.start(); t3.start(); t4.start(); } }
lock新特性替换上面方法
package pack;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Resource {
private String name;
private int count = 1;
private boolean flag = false;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void set(String name) {
lock.lock();
try {
while (flag) // 加了while会造成程序死掉
condition.await();
this.name = name + count++;
System.out.println(Thread.currentThread().getName() + "...生产者"
+ this.name);
flag = true;
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void out() {
lock.lock();
try {
while (!flag)
condition.await();
System.out.println(Thread.currentThread().getName() + "...消费者..."
+ name);
flag = false;
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
class Producer implements Runnable {
Resource res;
Producer(Resource res) {
this.res = res;
}
public void run() {
// TODO Auto-generated method stub
while (true)
res.set("+商品+");
}
}
class Consumer implements Runnable {
Resource res;
Consumer(Resource res) {
this.res = res;
}
public void run() {
// TODO Auto-generated method stub
while (true)
res.out();
}
}
public class Demo {
public static void main(String[] args) {
Resource res = new Resource();
Producer p = new Producer(res);
Consumer c = new Consumer(res);
Thread t1 = new Thread(p);
Thread t2 = new Thread(p);
Thread t3 = new Thread(c);
Thread t4 = new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
lock锁的优化 生产者消费者,线程间通信
package pack;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 这个flag判断语句依然要设置成while判断
* 如果设置成if t1 t2 线程是生产者 t3 t4 线程是消费者
* t1 t2 失去执行权 t3执行,然后producer_con.signal(); 这时t4 获取线程运行权,但是flag是false,t4睡眠
* t1 t2 由于一开始就执行过 不需要判断if语句,直接执行,,这时候 就会造成 生产2次
* @Description TODO
* @author WiKi
* @date 2014-11-30 下午2:07:41
*/
class Resource {
private String name;
private int count = 1;
private boolean flag = false;
Lock lock = new ReentrantLock();
Condition producer_con = lock.newCondition();
Condition consumer_con = lock.newCondition();
public void set(String name) throws InterruptedException {
lock.lock();
try {
while (flag) // 加了while会造成程序死掉
producer_con.await();
this.name = name + count++;
System.out.println(Thread.currentThread().getName() + "...生产者"
+ this.name);
flag = true;
consumer_con.signal();
} finally {
lock.unlock();
}
}
public void out() throws InterruptedException {
lock.lock();
try {
while (!flag)
consumer_con.await();
System.out.println(Thread.currentThread().getName() + "...消费者..."
+ name);
flag = false;
producer_con.signal();
} finally {
lock.unlock();
}
}
}
class Producer implements Runnable {
Resource res;
Producer(Resource res) {
this.res = res;
}
public void run() {
// TODO Auto-generated method stub
while (true)
try {
res.set("+商品+");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Consumer implements Runnable {
Resource res;
Consumer(Resource res) {
this.res = res;
}
public void run() {
// TODO Auto-generated method stub
while (true)
try {
res.out();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Demo {
public static void main(String[] args) {
Resource res = new Resource();
Producer p = new Producer(res);
Consumer c = new Consumer(res);
Thread t1 = new Thread(p);
Thread t2 = new Thread(p);
Thread t3 = new Thread(c);
Thread t4 = new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
多线程控制线程循环:就是控制while()的标记
package pack;
/**
* 控制线程循环
*/
class StopThread implements Runnable{
private boolean flag = true;
public void run() {
// TODO Auto-generated method stub
while(flag){
System.out.println("wiki");
}
}
public void changeflag(){
flag = !flag;
}
}
public class Demo{
public static void main(String[] args) {
StopThread st = new StopThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int count = 0;
while(true){
if(count++ == 60){
st.changeflag();
break;
}
System.out.println(Thread.currentThread().getName()+"::"+count);
}
}
}
停止冻结状态的线程
wait notify notifyAll 这些只能存在于synchronized 代码块里面,如果出现在其他地方会报 IllegalMonitorStateException 异常
如何停止线程?
只有一种,run方法结束.
开启多线程运行,运行代码通常是循环结构.
只要控制住循环,就可以让run方法结束,也就是线程结束.
特殊情况:
当线程处于了冻结状态, wait状态,
就不会读取到标记,那么线程就不会结束.
interrupt 中断线程. 将处于冻结状态的线程,强制恢复到运行状态,
当没有指定的方式让冻结的线程恢复到运行状态,这时需要对冻结进行清除.
强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束.
package pack;
/**
* 控制线程循环
*/
class StopThread implements Runnable{
private boolean flag = true;
public void run() {
// TODO Auto-generated method stub
while(flag){
try {
System.out.println("11111111");
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println(Thread.currentThread().getName()+"....Exception");
}
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeflag(){
flag = false;
}
}
public class Demo{
public static void main(String[] args) {
StopThread st = new StopThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int count = 0;
while(true){
if(count++ == 60){
st.changeflag();
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"::"+count);
}
System.out.println("over");
}
}
后台线程:,处于后台运行,任务是为其他线程提供服务
。也称为“守护线程”或“精灵线程”。JVM的垃圾回收就是典型的后台线程。
特点:若所有的前台线程都死亡,后台线程自动死亡。
设置后台线程:Thread对象setDaemon(true);
setDaemon(true)必须在start()调用前。否则出现IllegalThreadStateException异常;
前台线程创建的线程默认是前台线程;
判断是否是后台线程:使用Thread对象的isDaemon()方法;
并且当且仅当创建线程是后台线程时,新线程才是后台线程。
创建一个后台线程
package pack;
class Ticket implements Runnable{
public void run() {
// TODO Auto-generated method stub
while(true){
System.out.println(Thread.currentThread().getName());
}
}
}
public class Demo {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread t1 = new Thread(ticket);
Thread t2 = new Thread(ticket);
System.out.println("main thread");
t1.setDaemon(true);
t1.start();
t2.start(); //如果t2不运行的话,t1会运行几次,发现main线程 结束了,他也就结束了,不过有个时间间隔
//t2运行的话, t1和t2会交互执行
}
}
join 等待线程结束/死亡
package pack;
class JoinDemo implements Runnable {
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 70; i++) {
System.out.println(Thread.currentThread().getName() + "...." + i);
}
}
}
public class Demo {
public static void main(String[] args) throws InterruptedException {
JoinDemo jd = new JoinDemo();
Thread t1 = new Thread(jd);
Thread t2 = new Thread(jd);
t1.start();
// t1.join(); 当join放在这里,当执行到这里,main释放执行权,然后让t1线程死掉,main才恢复,才会继续执行后面
t2.start();
// t1.join(); 当join放这里,执行到这里,main释放执行权,t1,t2,2线程抢执行权,只有在t1执行完,main才恢复执行
//这是如果t2还没执行完, main和t2抢执行权
for (int i = 0; i < 60; i++) {
System.out.println(Thread.currentThread().getName() + "...main..."
+ "..." + i);
}
System.out.println("over");
}
}
线程的优先级
static int MAX_PRIORITY 线程可以具有的最高优先级。 10
static int MIN_PRIORITY 线程可以具有的最低优先级。 1
static int NORM_PRIORITY 分配给线程的默认优先级。 5
//t1.setPriority(Thread.MIN_PRIORITY);
yield用法:yield 暂停当前正在执行的线程对象,并执行其他线程。这个只是稍微减缓线程运行,可能那个线程还是自身
package pack;
class Ticket implements Runnable{
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<30;i++){
System.out.println(Thread.currentThread().toString());
Thread.yield();
}
}
}
public class Demo {
public static void main(String[] args) throws InterruptedException {
Ticket ticket = new Ticket();
Thread t1 = new Thread(ticket);
Thread t2 = new Thread(ticket);
// t1.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
System.out.println("over");
}
}
多线程的运用
package pack;
public class Demo {
public static void main(String[] args) {
new Thread() {
public void run() {
for (int i = 0; i < 30; i++) {
System.out.println(Thread.currentThread().getName() + "..."
+ i);
}
};
}.start();
Runnable r = new Runnable() {
public void run() {
for (int i = 0; i < 30; i++) {
System.out.println(Thread.currentThread().getName() + "..."
+ i);
}
}
};
new Thread(r).start();
for (int i = 0; i < 30; i++) {
System.out.println(Thread.currentThread().getName() + "..." + i);
}
}
}
浙公网安备 33010602011771号