1.多线程的优势
1) 进程之间不能共享内存,线程之间共享内存较容易。
2) 进程创建时,需要为其分配系统资源,但线程创建的代价较小
3)java语言内置了多线程功能支持,不是单纯的作为底层操作系统的调度方式,从而简化了java的多线程编程。
2.线程的创建和启动
java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。如下:
class FirstThread extends Thread
{//该方法通过继承Thread类创建的线程之间不能共享线程类的实例属性
private int i;
public void run()
{
for(;i<100;i++)
{
System.out.println(getName()+" "+i);
}
}
public static void main(String[] args)
{
for(int i=0;i<100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==20)
{//当i==20时,并不一定立即执行新创建的线程
new FirstThread().start();
new FirstThread().start();
}
}
}
}
class SecondThread implements Runnable
{//该方法创建的线程可实现实例属性的共享
private int i;
public void run()
{
for(;i<100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
public static void main(String[] args)
{
for(int i=0;i<100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==20)
{
SecondThread st=new SecondThread();
//下面两个新线程会交替执行run()方法,实现对实例属性i的共享
new Thread(st,"线程1").start();
new Thread(st,"线程2").start();
}
}
}
}
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class ThirdThread implements Callable<Integer>
{//具有返回值的线程执行体
public Integer call()
{
int i=0;
for(;i<100;i++)
{
System.out.println(Thread.currentThread().getName()+"变量i"+i);
}
return i;
}
public static void main(String[] args)
{
//Callable对象不能直接作为Thread的target,需要通过Future接口的实现类FutureTask关联
ThirdThread tt=new ThirdThread();
FutureTask<Integer> task=new FutureTask<Integer>(tt);
for(int i=0;i<100;i++)
{
System.out.println(Thread.currentThread().getName());
if(i==20)
{
new Thread(task,"返回值线程").start();
}
}
try
{
System.out.println("返回值:"+task.get());
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
2.线程的生命周期(线程的状态变化)
其中判断线程是否死亡的方法时isAlive()。
3.控制线程
3.1 join线程
当某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,知道加入的线程执行完为止。如下:
class JoinThread extends Thread
{
public JoinThread(String name)
{
super(name);
}
public void run()
{
for(int i=0;i<100;i++)
{
System.out.println(getName()+" "+i);
}
}
public static void main(String[] args) throws Exception
{
new JoinThread("新线程").start();
for(int i=0;i<100;i++)
{
if(i==20)
{//此时main线程被阻塞,jt和新线程开始交叉执行
JoinThread jt=new JoinThread("被Join的线程");
jt.start();
jt.join();
}
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
3.2 后台线程
特点:后台运行,为其他的线程提供服务,当所有前台线程死亡,后台线程会自动死亡。
class DaemonThread extends Thread
{
public void run()
{
for(int i=0;i<1000;i++)
{//此时一般不会执行到1000
System.out.println(getName()+" "+i);
}
}
public static void main(String[] args)
{
DaemonThread t=new DaemonThread();
t.setDaemon(true);
t.start();
for(int i=0;i<10;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
//程序执行到此,主程序结束,则后台线程也随之结束
}
}
3.3 线程睡眠
使用sleep()可以将当前正在执行的线程暂停一段时间,并进入阻塞状态,暂停期间,即使没有其他线程在执行,该线程也不会执行。
import java.util.*;
class SleepTest
{
public static void main(String[] args) throws Exception
{
for(int i=0;i<10;i++)
{
System.out.println("当前时间:"+new Date());
Thread.sleep(1000);//间隔1s输出当前时间
}
}
}
3.4 线程让步
使用yield()方法,可以将当前执行的线程暂停并进入就绪状态,然后由系统重新调度。但一般只有优先级大于等于该线程的就绪线程才会获得执行的机会。
class YieldTest extends Thread
{
public YieldTest(String name)
{
super(name);
}
public void run()
{
for(int i=0;i<50;i++)
{
System.out.println(getName()+" "+i);
if(i==20)
{
Thread.yield();
}
}
}
public static void main(String[] args)
{
YieldTest yt1=new YieldTest("高级");
yt1.setPriority(Thread.MAX_PRIORITY);//改变线程的优先级为最高
yt1.start();
YieldTest yt2=new YieldTest("低级");
yt2.setPriority(Thread.MIN_PRIORITY);
yt2.start();
}
}