什么是线程?
线程是一个程序里的不同执行路径
一般的程序是从一个入口出发,沿着唯一的路径走到终点,而线程则使唯一的路径变成多条路径
以下是单线程操作
class A extends Thread
{
public void run()
{
while(true)
{
System.out.println("hello world");
}
}
}
public class Thread1 {
public static void main(String[]args)
{
A aa=new A();
aa.run();
while(true)
{
System.out.println("hello JAVA");
}
}
}
因为aa.run没有执行完毕,下面的while循环就不会执行,所以就是一直输出“hello world“
再看看多线程操作
class A extends Thread
{
public void run()
{
while(true)
{
System.out.println("hello world");
}
}
}
public class Thread1 {
public static void main(String[]args)
{
A aa=new A();
aa.start();
while(true)
{
System.out.println("hello JAVA");
}
}
}
Thread中的start方法就是创建一个线程,并且自动调用run方法,直接调用run方法是不会创建一个线程的。
执行一个线程,其实就是执行一个线程里面的run方法,一个Thread对象不能调用两次start方法,否则会抛出异常。
单线程就是一条路径,从头到尾执行。
多线程就是有多条路径,每次都可以走不同的路径。
执行aa.start并不代表aa对象的线程就立刻执行,而是得到了能够被CPU执行的资格,也就是就绪的状态。!
创建线程的第二种方式:
class A implements Runnable
{
public void run()
{
while(true)
{
System.out.println("hello world");
}
}
}
public class Thread2 {
public static void main(String[]args)
{
A aa=new A();
Thread th=new Thread(aa);
th.start();
while(true)
{
System.out.println("hello JAVA");
}
}
}
Thread常用方法:
setName(String)设置名字
currentThread()返回正在执行线程的对象
getName()返回线程的名字
class A extends Thread
{
public void run()
{
System.out.println("hello world");
System.out.println(Thread.currentThread().getName());
}
}
public class Thread1
{
public static void main(String[]args)
{
A aa=new A();
aa.start();
System.out.println("hello JAVA");
System.out.println(Thread.currentThread().getName());
}
}
class A extends Thread
{
public void run()
{
System.out.println("hello world");
System.out.println(Thread.currentThread().getName());
}
}
public class Thread1 {
public static void main(String[]args)
{
A aa=new A();
aa.setName("123");
aa.start();
System.out.println("hello JAVA");
System.out.println(Thread.currentThread().getName());
}
}
Thread的sleep方法
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。
要捕获异常!
class A extends Thread
{
public void run()
{
for(int i=0;i<10;i++)
{
System.out.println(Thread.currentThread().getName()+i);
try{
Thread.sleep(1000);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
public class Thread1 {
public static void main(String[]args)
{
A aa=new A();
aa.start();
}
}
Thread的join方法:如a.join();暂停当前正在执行的线程,直到a的线程运行终止之后当前线程才有机会得到执行,注意:不是暂停a对象的线程,而是当前运行的线程
class A extends Thread
{
public void run()
{
for(int i=0;i<10;i++)
{
System.out.println(Thread.currentThread().getName()+i);
}
}
}
public class Thread1 {
public static void main(String[]args)
{
A aa=new A();
aa.start();
try{
aa.join();
}
catch(Exception e)
{
e.printStackTrace();
}
for(int i=0;i<10;i++)
{
System.out.println(Thread.currentThread().getName()+i);
}
}
}
Thread的优先级:getPriority:获取优先级
setPriority:设置优先级
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。
线程调度器用数字表现,范围从一到十,一个线程默认是5。
通常优先级高的比优先级低的要先执行,但并不是一定的!因为实际开发中并不单纯依赖优先级来决定优先级的运行顺序
class A implements Runnable{
public void run()
{
for(int i=0;i<10;i++)
{
System.out.println("A"+i);
}
}
}
class B implements Runnable{
public void run()
{
for(int i=0;i<10;i++)
{
System.out.println("B"+i);
}
}
}
public class Thread3 {
public static void main(String[]args)
{
Thread t1=new Thread(new A());
Thread t2=new Thread(new B());
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
}
}
优先级越高!越容易被CPU先调用!
线程的同步
卖票系统!
假如有三个地方,A,B,C同时卖票
假如代码写成这样
if(票数大于0)
{
买票
票数-1
}
当A发现票大于0的时候,本应该执行下一步,假如此时CPU切换的B线程的时候,发现票数大于0(因为在A线程里面,票数没有减一),当在B中发现票数大于0之后,假如CPU又切换到C线程里面,发现票数还是大于0(同理)假如票只有一张,那么此时就相当于一张票被卖了三次。
这将产生错误!
class A implements Runnable
{
private int tickets=100;
public void run()
{
while(true)
{
if(tickets>0)
{
System.out.println(Thread.currentThread().getName()+"正在卖出第"+tickets+"张票");
tickets--;
}
else
{
break;
}
}
}
}
public class Thread4 {
public static void main(String[]args)
{
A a=new A();
Thread t1=new Thread(a);
t1.start();
A b=new A();
Thread t2=new Thread(b);
t2.start();
}
}
以上代码运行结果:
每张票都被卖出去两次!!!这是不合理的
导致这个的原因是a对象和b对象都有一个属于自己的tickets 100
那么接下来看以下程序
class A implements Runnable
{
static int tickets=100;
public void run()
{
while(true)
{
if(tickets>0)
{
System.out.println(Thread.currentThread().getName()+"正在卖出第"+tickets+"张票");
tickets--;
}
else
{
break;
}
}
}
}
public class Thread4 {
public static void main(String[]args)
{
A a=new A();
Thread t1=new Thread(a);
t1.start();
A b=new A();
Thread t2=new Thread(b);
t2.start();
}
}
把票数改成静态的
结果是这样的:
那么来分析一下这个结果是为什么,当Thread-0发现票数是100的时候执行卖出操作,然后立刻切换的线程1然后发现还是100但是没有执行卖出操作又转换为线程0,此时减一然后就变成99、98、97、96、95、这个时候立刻切换成线程1执行卖出操作,打印出来,。
简单来说:CPU会在线程之间来回切换!
好的,重点来了!
Synchronized---同步
class A implements Runnable
{
static int tickets=100;
public void run()
{
while(true)
{
synchronized(this)
{
if(tickets>0)
{
System.out.println(Thread.currentThread().getName()+"正在卖出第"+tickets+"张票");
tickets--;
}
else
{
break;
}
}
}
}
}
public class Thread4 {
public static void main(String[]args)
{
A a=new A();
Thread t1=new Thread(a);
Thread t2=new Thread(a);
t1.start();
t2.start();
}
}
结果如下
synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。