1、简介

  多线程技术属于操作系统范围内的知识;

  进程与线程

  可以这么理解,一个应用程序就是一个进程,在一个进程中包含至少一个线程;进程就是线程的容器,真正工作、处理任务的是线程。

  进程是操作系统分配资源的基本单位;线程是操作系统进行调度,时间分配的基本单位;

  进程由内核对象和地址空间两部分构成,内核对象就是一小块记录进程信息的内存,只允许操作系统访问;地址空间就是存放数据和程序的空间;

2、多线程运行机制

  对于单个CPU,在每个时间点只能只能执行一个线程,多线程的实现是基于对时间片的轮回机制的,即为每一个线程分配一个极短的时间片;时间片结束了就执行另一个线程,关于时间片的分配是由操作系统完成的,应用程序无法改变。应用程序可以设置线程的优先级。

  关于线程的优先级,对于windows操作系统,线程的优先级是根据所在进程的优先级类和线程的相对优先级类进行确定的,方法如图:

  

  注意,进程优先级一般不要设置为real-time会出问题的。

  然后说一下优先级的作用,优先级越高,分配的时间片越长;优先级不等同于执行顺序,线程的执行顺序受操作系统的很多因素影响,优先级只可能是其中的一个因素,所以指望利用优先级控制线程的执行顺序是不现实的。

  另外不同语言对优先级的规定也不同,而且优先级适合操作系统和平台相关的,利用优先级控制程序,在一个平台中运行很好,而在另一个平台中就可能会出问题。

3、线程的生命周期(基于Java语言)

  new(创建线程)、run/start(执行线程)、block(阻塞线程)、wait(释放锁,并等待唤醒)、destroy(死亡)

  对于run和start  尽量选择用start  ,因为虽然run是线程真正的处理程序,但是调用run就相当于调用了一个方法,run不结束,是不会执行后面的语句的;而调用start会自动调用run,并且无论run是否运行完毕,都会执行后面的程序,这才是真正意义上启动一个线程;

4、基于Java 多线程的实现

  基于Java实现多线程有两种方式,一个是通过继承thread类,另一个是继承runnable接口;两种方式本质上没有太多区别,因为thread类本身也是继承了Runnable接口的,只不过在进行了一些封装而已。两种方式在使用上是由区别的,如果一个类已经继承了其他类,便不能再集成thread类了,所以只能使用第二种方法。

  继承于thread类的类,可以直接调用thread的方法;

  大概是这样的

public class testThread1 extend Thread
{
/**
*重写run方法
*/
public void run()
{
}
} //调用方式
testThread1 threadInstance = new testThread1 ();
threadInstance.start(); //自动执行run方法

方式一

  继承于runnable接口的类,必须实例化后,然后用实例化后的对象初始化一个thread对象;

  大概是这样的

public class testThread2 implements Runnable
{
/**
*重写run方法
*/
public void run()
{
}
} //调用方式
testThread2 threadInstance = new testThread2 ();
Thread real_threaInstance = new Thread(threadInstance );
real_threaInstance .start(); //自动执行run方法

方式二

  本质上都是对runnable的run方法进行重写,run中的函数就是线程要执行的函数。

5、基于Java的多线程通信

  多线程之间的通信自己分类,分为三种:(1)共享变量      (2)消息机制          (3)管道机制(暂时不了解还)

  (1)共享变量

  各个线程共享进程的地址空间,所以就都可以访问进程中的公共地址空间,这样在公共地址空间中的变量就可以被各个线程访问;如果进程中的地址空间被分配给某个线程,那么其他线程就不可以访问了。

  (2)消息机制

  主要介绍sleep   join    wait    notify    synchronized的应用

  synchronized:为obj对象加锁,调用方法 synchronized(obj){}   //obj是一个对象  只要继承于object类即可 如: string类型                在Java中,每一个继承于object类的对象都有一个琐,当对这个对象枷锁之后,其他线程便不能够再访问这个对象了;

  sleep:使线程休眠一定的时间,在休眠过程中不是释放锁

  wait: 有两种调用方式 wait(1000)  //指定休眠时间        wait()  //不指定休眠时间,在休眠过程中 会释放锁;wait()  必须放在synchronized代码块中,因为只有加锁之后,才可以释放锁,释放的就是synchronized(obj)  obj的锁;否则就会报异常;

  notify:唤醒一个wait线程

  从语法上来讲,wait()      与    notify()都必须位于synchronized块内;

  对于一个对象的锁,wait和notify是这样配合的:首先加锁,调用锁的wait方法,阻塞线程,然后等待这个锁的notify方法被调用,被调用之后,停止wait,执行线程后面的程序。

  子线程.join()  是阻塞主线程,等待子线程完成后再执行主线程;如:主线程中需要用到子线程的计算结果等情况

  可以利用消息机制  控制  线程的执行顺序;

6、代码示例

  以下代码实现了多个客户端与服务器端建立连接并发送消息的过程,至于服务器端对客户端发送消息,这一部分没有写好,因为多个线程在等待发送消息,所以发送的时候会随机选择一个客户端。

  服务器端关键代码:  

/**
*
* @method: jTextArea1KeyPressed() -by fjt
* @TODO: 判断是否按下Enter键
* @param evt void
*/
private void txtAreaSendKeyPressed(java.awt.event.KeyEvent evt) {
// TODO add your handling code here:
if(evt.getKeyChar() == '\n')
{
synchronized (Sendobj) {
Sendobj.notify();
} }
} ServerSocket server = null; //服务器
int socketNo = 0; //客户端编号
/***
*
* @method: btn_stopActionPerformed() -by fjt
* @TODO: 关闭服务器
* @param evt void
*/
private void btn_stopActionPerformed(java.awt.event.ActionEvent evt) {
// 关闭服务器
try {
server.close();
MessageRecord.append("服务器关闭成功……\n");
} catch (Exception e) {
// TODO: handle exception
MessageRecord.append("服务器关闭失败……\n" + e + "\n");
}
}
/****
*
* @method: btn_startActionPerformed() -by fjt
* @TODO: 开启服务器
* @param evt void
*/
private void btn_startActionPerformed(java.awt.event.ActionEvent evt) {
// 开启服务器
MessageRecord.append("服务器启动中……\n");
try {
server = new ServerSocket(4700);
MessageRecord.append("服务器启动成功,端口:4700\n");
} catch (Exception e) {
MessageRecord.append("服务器启动失败……\n" + e + "\n");
}
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
creatSocket(server);
}
}).start();
} /***
*
* @method: creatSocket() -by fjt
* @TODO: 创建套接字函数
* @param server void
*/
Object Sendobj = new Object(); //发送线程监控器
public void creatSocket(final ServerSocket server) {
try
{
final Socket socket = server.accept(); //等待客户端连接 如果有客户端连接,则产生一个socket 对象
final String currentSocket = Integer.toString(socketNo);
socketNo++;
MessageRecord.append("客户端 " + currentSocket + " 已连接\n");
//发送消息线程
Thread sendThread = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
synchronized (Sendobj) {
try
{ while(true)
{
PrintWriter sendMsg = new PrintWriter(socket.getOutputStream());
sendMsg.println(txtAreaSend.getText());
sendMsg.flush();
Sendobj.wait();
}
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}); sendThread.start(); //如果调用run,就会阻碍后面的语句执行
//接受客户端消息线程
String line;
try {
final BufferedReader is = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
PrintWriter os = new PrintWriter(socket.getOutputStream()); //接受客户端信息线程
new Thread(new Runnable() { @Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
MessageRecord.append("client " + currentSocket
+ " : " + is.readLine() + "\n");
} catch (Exception e) {
// TODO: handle exception
MessageRecord.append(currentSocket + "读取客户端消息异常\n"
+ e + "\n");
} }
}
}).start(); } catch (Exception e) {
// TODO: handle exception
MessageRecord.append(currentSocket + "通信出现异常\n" + e + "\n");
}
//创建新的监听线程
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
creatSocket(server);
}
}).start();
//开启发送消息线程
//sendThread.run();
} catch (Exception e)
{
// TODO: handle exception
MessageRecord.append("客户端连接出现异常\n" + e + "\n");
}
} /**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ServerWatch().setVisible(true);
}
});
}

服务器端

  客户端

package testSocketClient;
import java.net.*;
import java.io.*;
public class client
{
public static void main(String[] args)
{
System.out.println("Hello Client!!"); try
{
Socket socket=new Socket("127.0.0.1",4700);
BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
PrintWriter os=new PrintWriter(socket.getOutputStream());
BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String readline;
readline=sin.readLine(); //从系统标准输入读入一字符串
while(!readline.equals("bye"))
{
os.println(readline);
os.flush();
System.out.println("Client:"+readline);
System.out.println("Server:"+is.readLine());
readline=sin.readLine();
}
os.close(); //关闭Socket输出流
is.close(); //关闭Socket输入流
socket.close(); //关闭Socket
}
catch(Exception e)
{
System.out.println("错误信息:" + e);
}
} }

客户端

7、多线程编程中易出现的问题

  (1)资源共享,但没有处理好线程同步,读取脏数据

  (2)资源互斥,导致死锁问题

  (3)线程同步,即线程的执行顺序

  

基于JAVA语言的多线程技术的更多相关文章

  1. 基于Java语言开发jt808、jt809技术文章精华索引

    很多技术开发人员喜欢追逐最新的技术,如Node.js, go等语言,这些语言只是解决了某一个方面,如只是擅长异步高并发等等,却在企业管理后台开发方面提供的支持非常不够,造成项目团队技术选项失败,开发后 ...

  2. Java中的多线程技术全面详解

    本文主要从整体上介绍Java中的多线程技术,对于一些重要的基础概念会进行相对详细的介绍,若有叙述不清晰或是不正确的地方,希望大家指出,谢谢大家:) 为什么使用多线程 并发与并行 我们知道,在单核机器上 ...

  3. JFinal -基于Java 语言的MVC极速 web 开发框架

    JFinal概述 JFinal 是基于Java 语言的极速 web 开发框架,其核心设计目标是开发迅速.代码量少.学习简单.功能强大.轻量级.易扩展.Restful.在拥有Java语言所有优势的同时再 ...

  4. java语言体系的技术简介之JSP、Servlet、JDBC、JavaBean(Application)

    转自:https://zhangkunnan.iteye.com/blog/2040462 前言 Java语言 Java语言体系比较庞大,包括多个模块.从WEB项目应用角度讲有JSP.Servlet. ...

  5. Java 基础入门随笔(1) JavaSE版——java语言三种技术架构

    1.java语言的三种技术架构: J2SE(java 2 Platform Standard Edition):标准版,是为开发普通桌面和商务应用程序提供的解决方案.该技术体系是其他两者的基础,可以完 ...

  6. 单循环链表(基于java语言)

    public class CircleSinglyLinkList { private Node head; CircleSinglyLinkList(){ this.head = null; } C ...

  7. 《神经网络算法与实现-基于Java语言》的读书笔记

    文章提纲 全书总评 读书笔记 C1.初识神经网络 C2.神经网络是如何学习的 C3.有监督学习(运用感知机) C4.无监督学习(自组织映射) Rreferences(参考文献) 全书总评 书本印刷质量 ...

  8. 基于java语言的给cube添加custom view来实现权限控制

    今天是农历2014年的最后一个工作日了,在这里提前祝大家新年快乐.羊年大吉!当然本人今天也拿出来点儿真东西,做为献给大家的新年礼物,依次共勉. 下文主要讲述的是使用Java代码来完成对cube基于部门 ...

  9. 基于JAVA语言的selenium测试基础总结

    目录一.基本语句1.循环控制(break,continue)3.字符的替换(replace,repalceFirst,replaceAll,regex)4.字符串的连接("+",a ...

随机推荐

  1. 项目管理实践【六】自动同步数据库【Using Visual Studio with Source Control System to synchronize database automatically】

    在上一篇项目管理实践[五]自动编译和发布网站中,我们讲解了如何使用MSBuild+Robocopy+WebDeployment来自动编译和部署网站,今天,我们来看一下,如何使用MSBuild +SVN ...

  2. OLEDB和ODBC的区别

    ODBC(开放数据库互连):是Microsoft引进的一种早期数据库接口技术.它实际上是ADO的前身.早期的数据库连接是非常困难的. 每个数据库的格式都不一样,开发者得对他们所开发的每种数据库的底层A ...

  3. git基本命令--远程

    git clone: # clone到 <本地目录名> $ git clone <版本库的网址> <本地目录名> # 克隆版本库的时候,所使用的远程主机自动被Git ...

  4. 使用CodeFirst实现动态建库

    一.业务分析 以我们平时注册今目标为例,我们在注册今目标的过程中,具体步骤是这样的: 图1 今目标登陆流程 详细解释一下: 第一步:注册界面.输入手机号或者邮箱,点击确定进入基本信息界面. 第二步:基 ...

  5. Java is Pass-by-Value!

    Java is strictly pass-by-value. which means, when you pass a variable to a method, the method will j ...

  6. PHP图形处理函数试题

    一.问答题 1.取得当前安装的 GD 库的信息的函数是? 2.取得图像大小的函数是? 3.为一幅图像分配颜色 + alpha的函数是? 4.新建一个基于调色板的图像的函数是? 5.新建一个黑色图像的函 ...

  7. 贪心+bfs 或者 并查集 Codeforces Round #268 (Div. 2) D

    http://codeforces.com/contest/469/problem/D 题目大意: 给你一个长度为n数组,给你两个集合A.B,再给你两个数字a和b.A集合中的每一个数字x都也能在a集合 ...

  8. qmake pro工程设置

    ----我的生活,我的点点滴滴!! #以下是在terminal里面编译,想编译哪个就修改pro文件 #================================================= ...

  9. String s = new String("aa") 创建了几个对象?

    1 最近几个同学面试的时候出现了这样一个问题 刚听到这个题目的时候的确是不知所措: 经过网上的查找和自己的理解来解释一下这个题目的答案 答案是: 为什么呢??? 1 实现我们都知道创建实例有两种方法 ...

  10. Android OpenGL 入门示例----绘制三角形和正方形

    Android上对OpenGl的支持是无缝的,所以才有众多3D效果如此逼真的游戏,在Camera的一些流程中也有用到GLSurfaceView的情况.本文记录OpenGL在Android上的入门级示例 ...