线程--什么是进程
进程--概念
要解释线程,就必须明白什么是进程,就好象要搞清中国历史,就必须要了解春秋战国。
什么是进程呢?
进程是指运行中的应用程序,每个进程都有自己独立的地址空间(内存空间),比如用户点击桌面的IE浏览器,就启动了一个进程,操作系统就会为该进程分配独立的地址空间。当用户再次点击左面的IE浏览器,又启动了一个进程,操作系统将为新的进程分配新的独立的地址空间。目前操作系统都支持多进程。
要点:用户每启动一个进程,操作系统就会为该进程分配一个独立的内存空间。
线程--概念
在明白进程后,就比较容易理解线程的概念。
什么是线程呢?
是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。线程有就绪、阻塞和运行三种基本状态。
线程
1、线程是轻量级的进程
2、线程没有独立的地址空间(内存空间)
3、线程是由进程创建的(寄生在进程)
4、一个进程可以拥有多个线程-->这就是我们常说的多线程编程
5、线程有几种状态:
a、新建状态(new)
b、就绪状态(Runnable)
c、运行状态(Running)
d、阻塞状态(Blocked)
e、死亡状态(Dead)
线程有什么用处
java程序中流传一句话,不会使用线程就别跟别人说自己学过java。目前绝大部分应用程序都会涉及到多并发的问题。只要应用程序涉及到并发,就离不开多线程编程。
线程--如何使用
在java中一个类要当作线程来使用有两种方法。
1、继承Thread类,并重写run函数
2、实现Runnable接口,并重写run函数
因为java是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然不可能java设计者们提供了另外一个方式创建线程,就是通过实现Runnable接口来创建线程。
/**
* 演示如何通过继承Thread来开发线程
*/
public class Thread01 {
public static void main(String[] args) {
//创建一个 Cat对象
Cat cat=new Cat();
//启动线程
cat.start();//.start()会导致run函数运行
}
}
class Cat extends Thread{
int times=0;
//重写run函数
public void run(){
while(true){
//休眠一秒
//1000表示1000毫秒
try {
Thread.sleep(1000);//sleep就会让该线程进入到Blocked阻塞状态,并释放资源。
} catch (Exception e) {
e.printStackTrace();
}
times++;
System.out.println("hello,world!"+times);
if(times==10){
//退出线程
break;
}
}
}
}
通过Runnable接口来实现建立线程实例
/**
* 演示如何通过Runnable接口来开发线程
*/
public class Thread02{
public static void main(String []args){
Dog dog=new Dog();
//创建线程
Thread t=new Thread(dog);
//启动线程
t.start();
}
}
class Dog implements Runnable{//创建Runnable接口
public void run(){//重写run函数
int times=0;
while(true){
try{
Thread.sleep(1000);
}catch (Exception e) {
e.printStackTrace();
}
times++;
System.out.println("hello,wrold!"+times);
if(times==10){
break;
}
}
}
}
多线程实例演示
/**
*多线程Thread使用
*1、一个线程通过接收n来执行1+..+n得到和
*2、另一线程每隔1秒输出一次hello world!
*/
public class Thread03 {
public static void main(String[] args) {
Pig pig=new Pig(10);
Bird bird=new Bird(10);
//建立线程
Thread t1=new Thread(pig);
Thread t2=new Thread(bird);
//启动线程
t1.start();
t2.start();
}
}
//打印hello world!
class Pig implements Runnable{
int n=0;
int times=0;
public Pig(int n){
this.n=n;
}
public void run(){
while(true){
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
times++;
System.out.println("我是一个线程,正在输出第"+times+"个hello world!");
if(times==n){
break;
}
}
}
}
//算数学题
class Bird implements Runnable{//多线程时应使用implements接口来实现,不要使用extends继承
int n=0;
int res=0;
int times=0;
public Bird(int n){
this.n=n;
}
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
res+=(++times);
System.out.println("当前结果是:"+res);
if(times==n){
System.out.println("最后的结果是:"+res);
break;
}
}
}
}
线程--区别
线程--继承Thread VS实现Runnable的区别
从java的设计来看,通过继承Thread或者实现Runnable接口来创建线程本质上没有区别,从jdk帮助文档我们可以看到Thread类本身就实现了Runnable接口,如果一定要说它们有什么区别,总结几点:
1、尽可能使用实现Runnable接口的方式来创建线程
2、在使用Thread的时候只需要new一个实例出来,调用start()方法即可以启动一个线程,如: Thread test=new Thread();
test.start();
3、在使用Runnable的时候需要先new一个实现Runnable的实例,之后用Thread调用,如:
Test implements Runnable
Test t=new Test();
Thread test=new Thread(t);
tset.start();
线程--深入理解
线程对象只能启动一个线程
/**
* 功能:使用线程的注意事项
* 不论继承Thread或实现Rnunable接口都不能使用start启同一个线程2次
*/
public class Thread04 {
public static void main(String[] args) {
Cat cat1=new Cat();
cat1.start();
//cat1.start();同一个线程,不能启动2次
Dog dog1=new Dog();
Thread t=new Thread(dog1);
t.start();
//t.start();同一个线程,不能启动2次
}
}
//猫类
class Cat extends Thread{
public void run(){
System.out.println("11");
}
}
//狗类
class Dog implements Runnable{
public void run(){
System.out.println("2");
}
}
结论:不管是通过继承Thread,还是通过实现Runnable接口创建线程,它们的一个对象只能启动(即:start())一次。否则就会有异常抛出。
两种创建线程的方法的区别
创建线程有两种方法:1、继承Thread;2、实现Runnable接口;这两种方法有什么区别?
用实现Runnable接口的特点
1、用实现Runnable接口的方法创建对象可以避免java单继承机制带来的局限;
2、用实现Runnable接口的方法,可以实现多个线程共享同一段代码(数据);
因此建议大家如果你的程序有同步逻辑需求,则使用Runnable的方法来创建线程。
java线程的同步--提出问题
多线程的并发,给我们编程带来很多好处,完成更多更有效率的程序。但是也给我们带来线程安全问题。
java线程的同步--解决问题
解决问题的关键就是要保证容易出问题的代码的原子性,所谓原子性就是指:当a线程在执行某段代码的时候,别的线程必须等到a线程执行完后,它才能执行这段代码。也就是排队一个一个解决。
java处理线程两步的方法非常简单,只需要在需要同步的代码段,用:
synchronized(Object){你要同步的代码}
即可。
售票案例演示
/**
* 功能:使用线程的注意事项
* 线程并发同步锁synchronized(Object){}的使用
*/
public class Thread05 {
public static void main(String[] args) {
//定义一个售票窗口
TicketWindow tw1=new TicketWindow();
//使用三个线程同时启动
Thread t1=new Thread(tw1);
Thread t2=new Thread(tw1);
Thread t3=new Thread(tw1);
t1.start();
t2.start();
t3.start();
}
}
//售票窗口类
class TicketWindow implements Runnable {
//共有2000张票
private int nums=2000;
private Dog myDog=new Dog();
public void run() {
while(true){
//出票速度是1秒出一张
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
//认为if else要保证其原子性
//先判断是否还有票
synchronized(myDog){//synchronized(this){}为同步代码块
if(nums>0){
//显示售票信息
//Thread.currentThread().getName()得到当前线程的名字
System.out.println(Thread.currentThread().getName()+"正在售出第"+nums+"张票");
nums--;
}else{
//售票结束
break;
}
}
}
}
}
class Dog{
}