Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
一、线程名称
// 显示主线程名
Thread t = Thread.currentThread();
System.out.println("当前的线程名字是:" + t.getName());
t.setName("MyJavaThread");
System.out.println("当前的线程名字是:" + t.getName());
此时会打印,主线程名字 main,修改线程名称后打印 MyJavaThread。
二、使用一个新的线程执行代码
编写一个类继承Thread,并且重写其run方法:
public class MyThread extends Thread
{
@Override
//重写run方法
public void run() {
// TODO Auto-generated method stub
//super.run();
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
在main中创建一个线程对象,并且启动执行,分别打印1,2,3,4......100。
// 继承Thread类创建新线程
MyThread t = new MyThread();
t.start(); //启动线程
此时run方法中的循环是脱离程序执行的主线程的,以一个新的线程来执行代码。
三、多个线程交替执行
编写一个类继承Thread,并且重写其run方法:
public class MyThread extends Thread
{
@Override
//重写run方法
public void run() {
// TODO Auto-generated method stub
//super.run();
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
在main中创建一个多个线程对象,并且启动执行。
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.start(); //启动线程
t2.start(); //启动线程
t3.start(); //启动线程
此时循环执行300次,并且是三个线程交替执行的。
四、继承Runnable接口实现多线程
编写一个类继承Runnable,并且重写其run方法:
public class MyRunnable implements Runnable
{
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
在main中创建一个多个线程对象,并且启动执行。
MyRunnable myRun = new MyRunnable();
Thread t1 = new Thread(myRun);
Thread t2 = new Thread(myRun);
Thread t3 = new Thread(myRun);
t1.start();
t2.start();
t3.start();
此时循环执行300次,并且是三个线程交替执行的。
由于Runnable是一个接口,所以可以避免单继承的局限性。
五、使用多线程模拟抢票
版本一:
编写一个类继承Thread,并且重写其run方法:
public class MyThread extends Thread
{
private int count = 20; //一共20张票
private int num=0; //票的编号,自动增长,例如(1,2,3,4,。。。。)
@Override
//给方法加锁,设置同步方法,此时线程休眠Thread.sleep(500),锁并没有释放,所以其它线程仍然不能访问方法
public void run() {
while(true)
{
if(count <= 0) //票全部卖完的情况下,直接退出循环
break;
num++; //票号自动生成
count--; //票的数量自动减少
try {
Thread.sleep(100); //模拟网络延时
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢票成功,票号:" + num + ",票剩余:" + count);
}
}
}
在main方法中模拟三个人进行抢票:
MyThread t1 = new MyThread();
t1.setName("刘备");
MyThread t2 = new MyThread();
t2.setName("关羽");
MyThread t3 = new MyThread();
t3.setName("张飞");
System.out.println("刘关张开始抢票:");
t1.start();
t2.start();
t3.start();
此时,我们发现一共20张票,但是每个人都可以抢到20张票。不符合逻辑,无法实现MyThread类中的票的数量的资源共享。
版本二:
编写一个类继承Runnable,并且重写其run方法:
public class MyRunnable implements Runnable
{
private int count = 20; //一共20张票
private int num=0; //票的编号,自动增长,例如(1,2,3,4,。。。。)
@Override
public void run() {
while(true)
{
if(count <= 0) //票全部卖完的情况下,直接退出循环
break;
num++; //票号自动生成
count--; //票的数量自动减少
try {
Thread.sleep(100); //线程休眠,模拟网络延时
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢票成功,票号:" + num + ",票剩余:" + count);
}
}
}
在main方法中模拟三个人进行抢票:
MyRunnable myRun = new MyRunnable();
Thread t1 = new Thread(myRun);
t1.setName("刘备");
Thread t2 = new Thread(myRun);
t2.setName("关羽");
Thread t3 = new Thread(myRun);
t3.setName("张飞");
System.out.println("刘关张开始抢票:");
t1.start();
t2.start();
t3.start();
此时,我们发现一共20张票,也实现了3个人一共抢票20张,但是存在了多个线程同时访问num变量的情况,所以存在多个人抢到了同一张票的情况,即票号相同,也不符合逻辑。
版本三:
编写一个类继承Runnable,并且重写其run方法:
public class MyRunnable implements Runnable
{
private int count = 20; //一共20张票
private int num=0; //票的编号,自动增长,例如(1,2,3,4,。。。。)
@Override
//使用同步方法synchronized来优化,将整个方法加锁,没有退出方法,其它线程无法调用方法。
public synchronized void run() {
while(true)
{
if(count <= 0) //票全部卖完的情况下,直接退出循环
break;
num++; //票号自动生成
count--; //票的数量自动减少
try {
Thread.sleep(100); //模拟网络延时
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "抢票成功,票号:" + num + ",票剩余:" + count);
}
}
}
在main方法中模拟三个人进行抢票:
MyRunnable myRun = new MyRunnable();
Thread t1 = new Thread(myRun);
t1.setName("刘备");
Thread t2 = new Thread(myRun);
t2.setName("关羽");
Thread t3 = new Thread(myRun);
t3.setName("张飞");
System.out.println("刘关张开始抢票:");
t1.start();
t2.start();
t3.start();
此时,我们为了解决多个人同时抢到同一张票的情况,给run方法进行了synchronized关键字加锁,加锁之后,当前线程的run方法没有退出,其它线程无法访问run方法,解决了多个人抢到同一张票的问题,但是又出现了新问题,即一个人把所有的票都抢光了。
最终版本:
编写一个类继承Runnable,并且重写其run方法:
public class MyRunnable implements Runnable
{
private int count = 20; //一共20张票
private int num=0; //票的编号,自动增长,例如(1,2,3,4,。。。。)
@Override
public void run() {
while(true)
{
synchronized(this) //给代码块加锁
{
if(count <= 0) //票全部卖完的情况下,直接退出循环
break;
num++; //票号自动生成
count--; //票的数量自动减少
System.out.println(Thread.currentThread().getName() + "抢票成功,票号:" + num + ",票剩余:" + count);
}
try {
Thread.sleep(100); //模拟网络延时
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
此时,我们给固定的代码块加锁,解决了上述所有问题。