多线程概要

1.理解程序、进程、线程的概念
  程序可以理解为静态的代码
  进程可以理解为执行中的程序。
  线程可以理解为进程的进一步细分,程序的一条执行路径

实现多线程的两种方式:方式一:继承于Thread类;方式二:实现Runnable接口

方式一:继承于Thread类

 * Thread的常用方法:
 * 1.start():启动线程并执行相应的run()方法
 * 2.run():子线程要执行的代码放入run()方法中
 * 3.currentThread():静态的,调取当前的线程
 * 4.getName():获取此线程的名字
 * 5.setName():设置此线程的名字
 * 6.yield():调用此方法的线程释放当前CPU的执行权
 * 7.join():在A线程中调用B线程的join()方法,表示:当执行到此方法,A线程停止执行,直至B线程执行完毕,
 * A线程再接着join()之后的代码执行
 * 8.isAlive():判断当前线程是否还存活
 * 9.sleep(long l):显式的让当前线程睡眠l毫秒
 * 10.线程通信:wait()   notify()  notifyAll()
 * 
 * 设置线程的优先级
 * getPriority() :返回线程优先值 
   setPriority(int newPriority) :改变线程的优先级,
   设定优先级只能说抢到的概率大了。并不能决定谁优先。
 

class SubThread1 extends Thread {
	public void run() {
		for (int i = 1; i <= 100; i++) {
			// try {
			// Thread.currentThread().sleep(1000);
			// } catch (InterruptedException e) {
			// // TODO Auto-generated catch block
			// e.printStackTrace();
			// }
			System.out.println(Thread.currentThread().getName() + ":"
					+ Thread.currentThread().getPriority() + ":" + i);
		}
	}
}

public class TestThread1 {
	public static void main(String[] args) {

		SubThread1 st1 = new SubThread1();
		st1.setName("子线程1");
		st1.setPriority(Thread.MAX_PRIORITY);
		st1.start();
		Thread.currentThread().setName("========主线程");
		for (int i = 1; i <= 100; i++) {
			System.out.println(Thread.currentThread().getName() + ":"
					+ Thread.currentThread().getPriority() + ":" + i);
			// if(i % 10 == 0){
			// Thread.currentThread().yield();
			// }
			// if(i == 20){
			// try {
			// st1.join();
			// } catch (InterruptedException e) {
			// // TODO Auto-generated catch block
			// e.printStackTrace();
			// }
			// }
		}
		System.out.println(st1.isAlive());
	}
}

方式二:实现Runnable接口

//1.创建一个实现了Runnable接口的类
class PrintNum1 implements Runnable {
	//2.实现接口的抽象方法
	public void run() {
		// 子线程执行的代码
		for (int i = 1; i <= 100; i++) {
			if (i % 2 == 0) {
				System.out.println(Thread.currentThread().getName() + ":" + i);
			}
		}
	}
}

public class TestThread1 {
	public static void main(String[] args) {
		//3.创建一个Runnable接口实现类的对象
		PrintNum1 p = new PrintNum1();
//		p.start();
//		p.run();
		//要想启动一个多线程,必须调用start()
		//4.将此对象作为形参传递给Thread类的构造器中,创建Thread类的对象,此对象即为一个线程
		Thread t1 = new Thread(p);
		//5.调用start()方法:启动线程并执行run()
		t1.start();//启动线程;执行Thread对象生成时构造器形参的对象的run()方法。
		
		//再创建一个线程
		Thread t2 = new Thread(p);
		t2.start();
	}
}

 * 创建多线程的方式二:通过实现的方式
 * 
 * 对比一下继承的方式 vs 实现的方式
区别
继承Thread:       线程代码存放Thread子类run方法中。
实现Runnable:线程代码存在接口的子类的run方法。

 * 1.联系:public class Thread implements Runnable
两种方式的对比:联系:class Thread implements Runnable
             比较哪个好?实现的方式较好。①解决了单继承的局限性。②如果多个线程有共享数据的话,建议使用实现方式,同时,共享
            数据所在的类可以作为Runnable接口的实现类。

     

使用多线程的优点            
背景:只使用单个线程完成多个任务(调用多个方法),肯定比用多个线程来完成用的时间更短,为何仍需多线程呢?

多线程程序的优点:
提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
提高计算机系统CPU的利用率
改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改
            
线程分类:
Java中的线程分为两类:一种是守护线程,一种是用户线程。
*它们在几乎每个方面都是相同的,唯一的区别是判断JVM何时离开。
*守护线程是用来服务用户线程的,通过在start()方法前调用thread.setDaemon(true)可以把一个用户线程变成一个守护线程。
*Java垃圾回收就是一个典型的守护线程。
*若JVM中都是守护线程,当前JVM将退出。

3.线程的生命周期
JDK中用Thread.State枚举表示了线程的几种状态
要想实现多线程,必须在主线程中创建新的线程对象。Java语言使用Thread类及其子类的对象来表示线程,在它的一个完整的生命周期中通常要经历如下的五种状态:
新建: 当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件
运行:当就绪的线程被调度并获得处理器资源时,便进入运行状态, run()方法定义了线程的操作和功能
阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 并临时中止自己的执行,进入阻塞状态
死亡:线程完成了它的全部工作或线程被提前强制性地中止   

4.线性同步机制:
前提:如果我们创建的多个线程,存在着共享数据,那么就有可能出现线程的安全问题:当其中一个线程操作共享数据时,还未操作完成,
          另外的线程就参与进来,导致对共享数据的操作出现问题。
解决方式:要求一个线程操作共享数据时,只有当其完成操作完成共享数据,其它线程才有机会执行共享数据。
方式一:同步代码块:
        synchronized(同步监视器){
            //操作共享数据的代码
        }
    注:1.同步监视器:俗称锁,任何一个类的对象都可以才充当锁。要想保证线程的安全,必须要求所有的线程共用同一把锁!
          2.使用实现Runnable接口的方式创建多线程的话,同步代码块中的锁,可以考虑是this。如果使用继承Thread类的方式,慎用this!
          3.共享数据:多个线程需要共同操作的变量。   明确哪部分是操作共享数据的代码。

     方式二:同步方法:将操作共享数据的方法声明为synchronized。
        比如:public synchronized void show(){ //操作共享数据的代码}
    注:1.对于非静态的方法而言,使用同步的话,默认锁为:this。如果使用在继承的方式实现多线程的话,慎用!
          2.对于静态的方法,如果使用同步,默认的锁为:当前类本身。以单例的懒汉式为例。 Class clazz = Singleton.class

总结:释放锁:wait();
**当前线程的同步方法、同步代码块执行结束
**当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行。
**当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束
**当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁

    不释放锁: sleep()   yield()  suspend() (过时,可能导致死锁)
**线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行
**线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁(同步监视器)。
**应尽量避免使用suspend()和resume()来控制线程

死锁:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
死锁是我们在使用同步时,需要避免的问题!

5.线程的通信:如下的三个方法必须使用在同步代码块或同步方法中!
wait():当在同步中,执行到此方法,则此线程“等待”,直至其他线程执行notify()的方法,将其唤醒,唤醒后继续其wait()后的代码
notify()/notifyAll():在同步中,执行到此方法,则唤醒其他的某一个或所有的被wait的线程。

转载于:https://my.oschina.net/u/3544282/blog/1217806

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
需求分析: 1. 功能需求: 基于TCP协议的网络服务能力测试工具,需要支持以下功能: - 发送请求并接收响应 - 支持多线程 - 支持同时测试多个目标服务器 - 支持自定义请求内容和请求频率 2. 性能需求: 网络服务能力测试工具需要满足以下性能需求: - 支持高并发,能够同时测试多个目标服务器 - 支持高速数据传输,能够快速发送请求并接收响应 - 响应时间低,能够快速响应用户请求 3. 可靠性需求: 网络服务能力测试工具需要满足以下可靠性需求: - 稳定性高,运行稳定,不易崩溃 - 具备错误处理能力,能够处理异常情况 - 支持长时间运行,能够长时间测试目标服务器的性能 概要设计: 1. 架构设计: 网络服务能力测试工具采用C/S架构,客户端和服务器通过TCP协议进行通信。客户端发送请求给服务器,服务器接收请求并返回响应给客户端。 2. 逻辑设计: 客户端程序主要由以下模块组成: - 参数解析模块:解析命令行参数,包括目标服务器地址、端口号、请求内容、请求频率等。 - 网络通信模块:建立与目标服务器的TCP连接,并发送请求和接收响应。 - 多线程模块:支持多个线程同时运行,每个线程负责向一个目标服务器发送请求。 - 错误处理模块:处理异常情况,如网络连接失败、请求发送失败等。 服务器程序主要由以下模块组成: - 网络通信模块:监听客户端请求,接收请求并返回响应。 - 多线程模块:支持多个线程同时运行,每个线程负责处理一个客户端的请求。 - 错误处理模块:处理异常情况,如网络连接失败、请求处理失败等。 3. 技术选型: 网络服务能力测试工具采用C/C++语言进行开发,使用socket编程实现网络通信功能,使用多线程编程实现并发功能。在Windows平台下,可以使用Winsock库;在Linux平台下,可以使用Socket API。同时,可以使用第三方库如Boost.Asio来简化网络编程。 4. 接口设计: 客户端和服务器之间通过TCP协议进行通信,客户端发送请求,服务器返回响应。请求和响应的格式可以自定义,通常采用文本格式或二进制格式。客户端和服务器之间的接口可以由参数解析模块和网络通信模块共同实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值