先来两个例子,回顾启动线程两种方法:
1、实现Runnable接口
Runnable 接口只有一个方法。run()方法。
Thread newThread= new Thread(target);//target是接口类型
Runnable的run方法可以使用Thread的静态方法
public class ThreadTest1 {
//实现Runnable,实现run方法
public static void main(String[] args) {
Runner1 runner1=new Runner1();
Thread th=new Thread(runner1);
th.start();//启动其他线程必须有start()方法
for(int i=0;i<20;i++){
System.out.println("main方法线程----------:"+i);
}
}
static class Runner1 implements Runnable{
public void run(){
for(int i=0;i<20;i++){
System.out.println("Runner:"+i);
}
}
}
}
2、子类继承Thread,重写run方法;再实例化子类
class MyThread extends Thread{
public void run(){。。。}
}
MyThread myThread=new MyThread();
public class ThreadTest1 {
//继承Thread 重写run方法
public static void main(String[] args) {
Runner1 runner1=new Runner1();
runner1.start();
for(int i=0;i<20;i++){
System.out.println("main方法线程----------:"+i);
}
}
static class Runner1 extends Thread{
public void run(){
for(int i=0;i<20;i++){
System.out.println("Runner:"+i);
}
}
}
}
线程概念
单线程的程序只有一个顺序执行流;
多线程的程序可以包含多个顺序执行流,多个顺序流之间互不干扰;
一句话:线程是程序里不同的执行路径;
进程是分配资源单位,静态的;线程是调度、执行单位,动态的;
线程的优势
线程是共享的环境:进程代码段、进程的公有数据等。
线程可以共享内存,进程不能;
多线程实现多任务比多进程的效率高;
java语言内置了多线程功能支持,而不是单纯的作为底层操作系统的调度方式,从而简化java的多线程编程。
线程创建和启动
Thread类代表线程,所有线程对象都是这个类或子类的实例。
run()代表线程要完成的任务,即线程执行体
start()启动多线程
main()主方法,代表主线程的线程执行体,默认的
Thread.currentThread():静态方法,返回当前正在执行的线程
getName():获取线程名,例如Thread-0、Thread-1等
创建:集成Thread类,实现Runnable、Callable接口,可以实现多线程
生命周期
就绪态、运行态、等待态
状态转换
线程死亡:线程正常结束、抛出异常或错误;
stop()方法来结束线程,容易导致死锁,通常不推荐使用,
isAlive()检查线程生命
控制线程
join()让一个线程等待另一个线程,把分支线程再合并回来。
/**
* join合并线程
* @author bobo
* 未合并前,main方法先执行完,再执行t2
*把t2合并回来,直到t2执行完了,再执行main方法
*/
public class TestJoin {
public static void main(String[] args) {
MyThread2 t2 = new MyThread2("t2");
t2.start();
try {
t2.join();
} catch (InterruptedException e) {
}
for(int i=0;i<=10;i++){
System.out.println("i am mian Thread");
}
}
public static class MyThread2 extends Thread{
MyThread2 (String s){
super(s);
}
public void run(){
for(int i=0;i<=10;i++){
System.out.println("i am " +getName());
try {
sleep(1000);
} catch (InterruptedException e) {
return;
}
}
}
}
}
Sleep()线程睡眠
public synchronized void method() throws Exception {
Thread.sleep(2500);//睡眠2.5秒,这期间其他线程不能占用
b = 2000;
}
yield()线程让步
/**
* 让出cpu一会,让给其他线程执行一会儿
* @author bobo
*
*/
public class testYield {
public static void main(String[] args) {
MyThread3 t1 = new MyThread3("t1");
MyThread3 t2 = new MyThread3("t2");
t1.start();
t2.start();
}
static class MyThread3 extends Thread{
MyThread3(String s){
super(s);
}
public void run(){
for(int i=0;i<=100;i++){
System.out.println(getName()+":"+ i);
System.out.println(Thread.currentThread().isAlive());
if(i % 10==0){
yield();//让出cpu
}
}
}
}
}
线程同步和死锁
Synchronized关键字,保证共享数据的完整性。保证在任一时刻只能有一个线程访问。
1、public snchronizedvoid add(){}//当前方法锁定
2、synchronized(this){//锁机制,锁定当前,保证了原子性,不会有第二个线程进来打断}
/**
* 同步,两个线程,一个的执行要拿到另一个线程给的资源,否则就是阻塞状态
* @author bobo
*
*/
public class TestSynchronized implements Runnable {
Timer t=new Timer();
public static void main(String[] args) {
TestSynchronized test=new TestSynchronized();
Thread t1=new Thread(test);
Thread t2=new Thread(test);
t1.setName("T1");
t2.setName("T2");
t1.start();
t2.start();
}
static class Timer{
private static int num=0;
public synchronized void add(String name){
num++;
try{
Thread.sleep(100);
}catch(InterruptedException e){
}
System.out.println(name+",你是第【"+num+"】个使用timer的线程!");
}
}
@Override
public void run() {
t.add(Thread.currentThread().getName());
}
}
死锁
我的理解是:当多个线程有共享资源,但是互相等待对象释放资源。
下面例子产生了死锁,两个线程都抓着资源不放,等待对方释放资源,但最终谁也等不到,而产生了死锁。
public class TestDeadLock implements Runnable {
public int flag=1;
static Object o1=new Object(),o2=new Object();
@Override
public void run() {
System.out.println("flag="+flag);
if(flag==1){
synchronized(o1){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(o2){
System.out.println("11");
}
}
}
if(flag==0){
synchronized(o2){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(o1){
System.out.println("00");
}
}
}
}
public static void main(String[] args) {
TestDeadLock dl=new TestDeadLock();
TestDeadLock dl2=new TestDeadLock();
dl.flag=1;
dl2.flag=0;
Thread t1=new Thread(dl);
Thread t2=new Thread(dl2);
t1.start();
t2.start();
}
}
以上是线程的基本知识,后面还会有很多地方会用到多线程,再一一介绍,既然有同步,就会有一个种生产者消费者的情况产生,后一个介绍,生产者和消费者的例子。