java多线程并发编程

                       java多线程并发编程

线程的基本概念

多线程是在 Windows 和 Linux 等操作系统都支持的重要特性它的特点就是可以在同一个程序中同时执行多段代码、同时完成多项工作工作。

在面向对象的开发过程中,我们通过使用对象,可将一个程序分割成相互独立的区域。我们通常也需要将一个程序转换成多个独立运行的子任务。象这样的每个子任务都叫作一个“线程”(Thread)。编写程序时,可将每个线程都想象成独立运行,而且都有自己的专用 CPU,其实主要是 CPU 占用的时间,我们利用微分的思想去思考当每个线程占用的时间足够小并且这样的占用间隙也足够小时,就可以人为的去理解这些线程是被同时执行的了。当然,现代计算机技术会实际为我们自动分割 CPU 的时间,我们通常不必关心这些细节问题,只需要理解时间片段的实现线程机制即可。事实上在 Java 中编写多线程的代码是相当简便的。

这时理解一些定义对以后的学习很有帮助。“进程”是指一种“自包容”的运行程序,有自己的地址空间。“多任务”操作系统能同时运行多个进程(程序)——但实际是由于 CPU 分时机制的作用,使每个进程都能循环获得自己的 CPU 时间片。但由于轮换速度非常快,使得所有程序好象是在“同时”运行一样。“线程”是进程内部单一的一个顺序控制流。因此,一个进程可能容纳了多个同时执行的线程。在这里插入图片描述

多线程的应用范围很广。但在一般情况下,程序的一些部分同特定的事件或资源联系在一起,同时又不想为它而暂停程序其他部分的执行。这样一来,就可考虑创建一个线程,令其与那个事件或资源关联到一起,并让它独立于主程序运行。一个很好的例子便是“Quit”或“退出”按钮——我们并不希望在程序的每一部分代码中都轮询这个按钮,同时又希望该按钮能及时地作出响应(使程序看起来似乎经常都在轮询它)。事实上,多线程最主要的一个用途就是构建一个“反应灵敏”的用户界面。例如开启一款游戏就是在你的计算机中开启了一个进程,而里面的游戏人物角色分别都是属于特定的一个线程,可以认为在界面程序开发过程中,线程的使用是不可避免的。我们在使用 Java 这门高级语言开发时,多线程的启动、暂停和结束都是需要着重了解的多线程程序实现重要知识点。主线程当 Java 程序启动运行时,一个线程便立刻运行,该线程被称为程序的主线程(main thread),因为它是程序开始时就执行的。主线程的重要性体现在两方面: 其他子线程由主线程产生

通常主线程是最后完成执行,因为它负责善后工作

尽管主线程在程序启动时自动创建,但它可以由一个 Thread 对象控制。为此,你必须调用方法 currentThread()获得它的一个引用,currentThread()是 Thread 类的公有的静态成员。它的通常形式如下:

  static Thread currentThread( )

该方法返回一个调用它的线程的引用。一旦你获得主线程的引用,你就可以像控制其他线程那样控制主线程:

public class TestMainThread {

public static void main(String[] args) {
	// 每个程序运行至少有一个线程,该线程被称作主线程
	System.out.println("程序go...");
	//取得主线程
	Thread  mainThread = Thread.currentThread();
	//阻塞三秒钟
	try {
		mainThread.sleep(3000);
		System.out.println("  ...三秒没睡醒,再睡两秒");
		mainThread.sleep(2000);
	} catch (InterruptedException e) {   //被打断异常
		e.printStackTrace();
	}
	System.out.println("程序end");
}

}
运行结果:
image.png

过 3 秒后:
image.png

再过 2 秒后:

线程的优先级在一些特殊的多线程程序中起着重要的作用,但非必要的话,一般都不需要设置线程的优先级。

创建线程的方法一共有三种

第一种是直接实现 java.lang.Runnable 接口

第二种衍生于第一种,即继承 Runnable 的实现类 java.lang.Thread 类型

第三种通过实现可以通过实现 java.util.concurrent.Callable 接口创建线程创建线程,跟前面实现 Runnable 接口相比,Callable 的方法可以有返回值,并且可以抛出异常。

创建线程

在传统的 Java 编程中,创建一个线程非常简单、最直接的方法就是从线程类 java.lang.Thread 继承。
在缺省情况下,线程类可以被所有的 Java 应用程序调用。

构造方法 摘要
Thread() 分配一个新的 Thread 对象。
Thread(Runnable target) 分配一个新的 Thread 对象。
Thread(Runnable target, String name) 分配一个新的 Thread 对象。
Thread(String name) 分配一个新的 Thread 对象。
Thread(ThreadGroup group, Runnable target) 分配一个新的 Thread 对象。
Thread(ThreadGroup group, Runnable target, String name) 分配一个新的 Thread 对象,使其具有 target 作为其运行对象,具有指定的 name 作为其名称,属于 group 引用的线程组。
Thread(ThreadGroup group, Runnable target, String name, long stackSize) 分配一个新的 Thread 对象,以便它具有 target 作为其运行对象,将指定的 name 正如其名,以及属于该线程组由称作 group ,并具有指定的 堆栈大小 。
Thread(ThreadGroup group, String name) 分配一个新的 Thread 对象。
为了使用线程类,需要了解 The java.lang.Thread 类中定义的五个方法:

Thread 常用方法 摘要
run() 该方法用于线程的执行。你需要重载该方法,以便让线程做特定的工作。
start() 该方法使得线程启动 run()方法。
stop() 该方法同 start()方法的作用相反,用于停止线程的运行。
suspend() 该方法同 stop()方法不同的是,它并不终止未完成的线程,而只是挂起线程,以后还可恢复。
resume() 该方法重新启动已经挂起的线程。
创建一个线程,在这个线程中每 100 毫秒打印输出一个计数器,一共打印 100 次

//自定义线程A
public class MyThreadA extends Thread {

int count=0; //计数器

@Override
public void run() {
	// 并发的线程逻辑:100ms递增+1并打印一次,打印100次  (10s)
	try {
		while(count<100) {
			System.out.println("count="+count++);
		    this.sleep(100);
		}
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
}

}
调用 MyThreadA 线程代码:

public class TestThd1 {

public static void main(String[] args) {
	// TODO Auto-generated method stub
	// TODO Auto-generated method stub
    System.out.println("程序TestThd1  go...");

    //创建线程
    MyThreadA thdA1 = new MyThreadA();
    //启动线程
    //thdA1.run();   //启动线程不可以使用run,启动使用start()
    thdA1.start();
System.out.println("程序TestThd1  end,主线程over");

}

}
运行结果为:

在主线程停止后,子线程 thdA1 继续运行,从 0 输出,每隔 100 毫秒递增输出计数器:
在这里插入图片描述

直至 99 结束。

使用构造器,可以创建"命名"的线程:

//自定义线程B —一个被命名的线程
class MyThreadB extends Thread {

int count=0; //计数器

public   MyThreadB(String name) {
	super(name);
}

@Override
public void run() {
	// 并发的线程逻辑:100ms递增+1并打印一次,打印30次  (3s)
	try {
		while(count<30) {
			System.out.println(this.getName()+"线程.count="+count++);
		    this.sleep(100);
		}
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
}

}

public class TestThd2 {

public static void main(String[] args) {
     System.out.println("程序3go...");

    //创建线程
    MyThreadB thdB1 = new MyThreadB("1号线程");
    MyThreadB thdB2 = new MyThreadB("2号线程");
    MyThreadB thdB3 = new MyThreadB("3号线程");

    try {
    	  //启动线程
		Thread.currentThread().sleep(3000);
		thdB1.start();
		Thread.currentThread().sleep(2800);
		thdB2.start();
		Thread.currentThread().sleep(800);
		thdB3.start();
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

	System.out.println("程序3end,主线程over");
} 

}
运行结果:
image.png

由于 CPU 争用情况的随机性,每次运行代码结果都有一些不同,每个线程实例维护着自己的一个 couter 计数器变量。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值