Java学习——多线程

前言

  记得本科时最开始听到多线程时,感觉好复杂啊。又是好多种状态啊:运行(running)、挂起(suspend)、恢复(resume)、阻塞(block)、终止(terminate)。又是各种优先级啊。还涉及到并发处理中的各种问题什么什么的。其实现在想想,在Java中,万物皆对象嘛,线程也不例外嘛。Java中的线程类是Thread,对于线程的操作也就封装在它里面了。它肯定是有已经写好的类供你使用了,我们要做的就是按照规矩和需要调其中的方法就好。当然,感觉要是想弄明白多线程的底层原理肯定还是特别难的。

Thread类里面的几个简单方法

  首先要知道当开始运行程序开始运行时,肯定是开启了一个线程啊(也肯定会会有进程吧,进程线程区别后面搞明白再说)。在一般Java的main里面程序开始执行时,当然也会开启一个线程。可以通过Thread.CurrentThread()来得到这个线程的引用,因为不需要new 对象,我们可以想到这个方法是静态的方法。可以找到Thread类中有这个静态方法。
public static native Thread currentThread();
这里的关键字native应该是告诉编译器(其实是JVM)调用的方法在外部定义,关键字native现在还没搞明白。这个方法前面是Thread这个类名,说明这个方法的返回是一个Thread的对象。
  下面的程序先是得到main里的Thread的引用,然后演示几种简单的方法用途。

package threadDemo;

public class ThreadDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread t = Thread.currentThread();
		System.out.println("线程t的名字:"+t.getName());
		System.out.println("线程t的id:"+t.getId());
		System.out.println("线程t的优先级:"+t.getPriority());
		System.out.println("线程t的状态:"+t.getState());
		System.out.println("线程t的toString():"+t.toString());
		t.setName("myThread");
		System.out.println("线程t的名字:"+t.getName());
		t.setPriority(4);
		System.out.println("线程t的优先级:"+t.getPriority());
		System.out.println("线程t的toString:"+t.toString());		
	}
}

在这里插入图片描述
getName():得到这个线程的名字,可以通过setName()的方法来改变它
getId:得到这个线程Id,Id的话就是能唯一表示这个线程的东西吧。
getPriority():得到这个线程的优先级,Java线程的优先级从底到高有1、2、3…10级,也就是10级是最重要的,默认会为5可以通过setPriority()的方法来设置线程的优先级。
getState():得到线程当前的状态,按照官方文档,线程一个有6种状态。
  NEW:这个状态是线程已经new出来了但是还没有启动。
  RUNNABLE:这个线程正在运行。
  BLOCKED:这个线程正在等待monitor lock。关于锁,现在只知道好像是一段代码块被锁住的话,这个代码块不会进行多线程模式,也就是它会一直运行,而不会让给别的线程。
  WAITING:这个线程要等待别的线程执行完某项操作,这里它的等待时间是不确定的,就是它不知道它要等多久吧。
  TIMED_WAITING:这个状态跟上面的差不多,也是等待别的线程完成某项操作,只不过这里它知道它还要等多长时间。
  TERMINATED:结束这个线程呗
toString():这个方法本来是Thread父类Object里的方法,这里被重写了,一般这个方法都会被重写的。它在这里返回的是Thread’s name, priority, and thread group.

创建一个线程的方法

  前面我们从main里面得到的线程是系统自动帮我们创建的线程,而我们要自己创建一个线程要怎么办咧。一般是有两种方法吧。一是实现Runable接口二是继承Thread类
(1)实现Runable接口
看下面的代码:

package threadDemo;
public class ThreadDemo {
	public static Thread mainThread;

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread1 t1= new Thread1();
		  mainThread = Thread.currentThread();
		
		for (int i=0;i<2;i++) {
			System.out.println("MainThread is running");
			System.out.println("t1线程当前的状态:"+t1.t1.getState());
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
class Thread1 implements Runnable{
	Thread t1;
	
	Thread1(){
		 t1 = new Thread(this,"Thread1");
		 System.out.println("new完后t1的状态:"+t1.getState());
		 t1.start();
		 System.out.println("start()后t1的状态:"+t1.getState());
	}	
	@Override
	public  void run() {
		// TODO Auto-generated method stub
		 
		for (int i=0;i<1;i++) {
			System.out.println("t1 is running");
			System.out.println("mainThread线程当前的状态:"+ThreadDemo.mainThread.getState());
			try {
				Thread.sleep(999);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

在这里插入图片描述
直接在同一个包里创建另一个类Thread1 ,并让它实现Runnable接口,并重写方法run()。run方法能够像主线程那样调用其他方法,引用其他类,声明变量。仅有的不同是run()在程序中确立另一个并发的线程执行入口。当run()返回时,该线程结束。
这个类前面不能是public额。public的类的类名必须要和文件名相同的。在Thread1的构造函数里new一个线程,并start。Console栏显示了线程在运行时的一些状态。关于Thread的构造函数还有些问题要讨论。
(2)继承Thread类

package threadDemo;
public class ThreadDemo {
	public static Thread mainThread;

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread1 t1= new Thread1();
		t1.start();
		
		  mainThread = Thread.currentThread();
		for (int i=0;i<3;i++) {
			System.out.println("MainThread is running");
			System.out.println("t1线程当前的状态:"+t1.getState());
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
class Thread1 extends Thread{
	@Override
	public  void run() {
		// TODO Auto-generated method stub
		 
		for (int i=0;i<2;i++) {
			System.out.println("t1 is running");
			System.out.println("mainThread线程当前的状态:"+ThreadDemo.mainThread.getState());
			try {
				Thread.sleep(980);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

在这里插入图片描述
其实和第一种没有太大区别,也必须要重写run()方法,追求本质的话,它们两应该是一样的。

线程结束

  另外,一般需要主线程最后结束。前面的两个程序是因为主线程里sleep的时间较t1线程长,所以主线程是最后结束的。然而正常情况下怎么样可以知道其他线程是否结束了,(难道不可以getState()),参考资料上说的可以通过线程类中isAlive()方法来判断,如果返回值是true,则线程仍在运行。但是这个方法很少用到,等待线程结束经常用join()方法,需要用try,catch围住。下面代码就是改了下t1线程的运行时间,并在main线程里用lt1.join()来等待t1线程结束。

package threadDemo;
public class ThreadDemo {
	public static Thread mainThread;

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Thread1 t1= new Thread1();
		t1.start();
		
		  mainThread = Thread.currentThread();
		for (int i=0;i<1;i++) {
			System.out.println("MainThread is running");
			System.out.println("t1线程当前的状态:"+t1.getState());
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		try {
			t1.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("t1线程当前的状态:"+t1.getState());
	}
}
class Thread1 extends Thread{
	@Override
	public  void run() {
		// TODO Auto-generated method stub
		 
		for (int i=0;i<4;i++) {
			System.out.println("t1 is running");
			System.out.println("mainThread线程当前的状态:"+ThreadDemo.mainThread.getState());
			try {
				Thread.sleep(980);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

在这里插入图片描述
  还有一些其他的问题需要以后讨论:
线程优先级。这个还好就是优先级高的占用cpu的时间长。
线程同步。这里涉及到管程,以我现在浅薄的理解,就是为了一个线程正在改某个数据,而另一个线程却要读这个数据。有时需要某个线程获得管程,然后其他的一些线程就需要挂起,直到第一个线程退出管程。这里可能理解的还不对。
线程间通信
线程锁
线程的挂起恢复和终止

参考:

Java入门经典(强烈推荐).pdf(原谅我没找到书的作者)
jdk官方文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值