线程的创建4种方式:
(1)继承Thread类—实现run方法,返回类型是void
(2)实现Runnable接口------实现run方法,返回类型是void 多线程(一个资源同时被2个及2个以上线程访问,容易出现死锁,采用同步解决)解决采用线程同步
(3)通过Callable和FutureTask创建线程
(4)通过线程池创建线程ExecutorServiceexecutor=Executors.newFixedThreadPool
注意: 前2个无返回值,后2个有返回值
1)继承Thread类创建线程
package cn.kgc.tangcco.chengxiangjain.xiancheng;
/**
* 1)继承Thread类创建线程
*/
public class Test1 extends Thread {
public void run() {
test();
}
public void test() {
System.out.println("-----------a-");
System.out.println("-----------b-");
System.out.println("-----------c-");
System.out.println("-----------d-");
}
// main方法会自动调用,就是一个标准的主线程
public static void main(String[] args) {
// 提问,有没有办法在test方法内容执行时,主方法的内容继续执行?----test方法必须时另启动一个线程
System.out.println("*******1");
System.out.println("*******2");
Test1 test1 = new Test1();// 创建一个线程对象
test1.start();// 调用线程启动方法,会自动执行run方法
System.out.println("*******3"); // 它必须等着test方法中所有内容执行结束后才会执行
try {
Thread.sleep(1 * 1000); // 让主线程先暂时修饰1秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("*******4");
}
}
2)实现Runnable接口创建线程
package cn.kgc.tangcco.chengxiangjain.xiancheng;
/**
* 2)实现Runnable接口创建线程
*/
public class Test2 implements Runnable {
int count = 1;
// synchronized 同步要求每次这个资源只允许一个线程访问
public synchronized void run() {
count++;
System.out.println(Thread.currentThread().getName() + "," + count);
}
// main方法会自动调用,就是一个标准的主线程
public static void main(String[] args) {
// 提问,有没有办法在test方法内容执行时,主方法的内容继续执行?----test方法必须时另启动一个线程
System.out.println("*******1");
System.out.println("*******2");
Test2 test1 = new Test2();// 创建一个
Test2 test2 = new Test2();// 创建一个
// 如果下面2个线程中使用的资源是同一个都是test1,那么2个子线程可能在同一个时间段都对count进行操作
// 这个count来源于对象test1(2个小孩同时抢了一个饼,那么这个饼进出现的资源死锁)
Thread t1 = new Thread(test1, "lily"); // 一个线程对象
Thread t2 = new Thread(test1, "lucy"); // 一个线程对象
t1.start();
t2.start();
System.out.println("*******3"); // 它必须等着test方法中所有内容执行结束后才会执
System.out.println("*******4");
}
}
3)使用Callable和Future创建线程
package cn.kgc.tangcco.chengxiangjain.xiancheng;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
* 3)使用Callable和Future创建线程
*/
//具有返回值的
public class Test3 implements Callable<Object> {
// 重写call方法,返回Object类型
@Override
public Object call() throws Exception {
System.out.println(Thread.currentThread().getName() + "我是通过实现Callable接口被FutureTask包装实现的线程");
return null;
}
}
class Test5 {
public static void main(String[] args) {
Callable<Object> oneCallable = new Test3();
// FutureTacsk对Callable对象进行包装
FutureTask<Object> oneTask = new FutureTask<Object>(oneCallable);
Thread t = new Thread(oneTask);
t.start();
}
}
4)使用线程池例如用Executor框架
package cn.kgc.tangcco.chengxiangjain.xiancheng;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 4)使用线程池例如用Executor框架
*/
public class Test4 {
public static void main(String[] args) {
// 创建一个线程池,固定线程的数量是5个
ExecutorService executor = Executors.newFixedThreadPool(5);
// 注册线程--注册的数量是5个
for (int i = 0; i < 5; i++) {
RunnableThread r1 = new RunnableThread();
executor.execute(r1);
}
// 关闭线程池
executor.shutdown();
}
}
class RunnableThread implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName() + "通过线程池创建线程");
}
}
经典案例:多线程卖票
package cn.kgc.tangcco.chengxiangjain.xiancheng;
public class Site implements Runnable {
private int count = 10;// 总票数
private int num = 0;// 累计买的票数
@Override
public void run() {
// Thread.currentThread():当前线程
System.out.println(Thread.currentThread().getName() + "进入");
while (true) {
/*
* synchronized: 一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,
* 一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
* 二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,
* 另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
* 三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,
* 其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
* 四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,
* 它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
*/
synchronized (this) {
if (count <= 0) {
break;
}
num++;
count--;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "买的第" + num + "张票,剩余" + count + "张票");
}
}
}
}
package cn.kgc.tangcco.chengxiangjain.xiancheng;
public class Test {
public static void main(String[] args) {
Site site = new Site();
// 创建了3个线程对象
Thread person1 = new Thread(site, "lily");
Thread person2 = new Thread(site, "lucy");
Thread person3 = new Thread(site, "黄牛");
System.out.println("********买票情况********");
// 都会调用run方法
person1.start();
person2.start();
person3.start();
}
}