/*
多线程: 进程:正在执行中的程序,一个应用程序启动后在内存中运行的那片空间。进程具有动态性和并发性。 线程:进程中的一个执行单元。负责进程中的程序的运行的。一个进程中至少要有一个线程。
一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。 程序启动了多线程,有什么应用呢?
可以实现多部分程序同时执行。专业术语称之为 并发。 多线程的使用可以合理使用cpu的资源,如果线程过多会导致降低性能。 cpu在处理程序时是通过快速切换完成的。在我们看来好像随机一样。
*/
 //03-多线程-主线程的运行方式&创建线程的第一种方式。
/*
通过代码来演示之前和之后的区别。 在之前的代码中,jvm启动后,必然有一个执行路径(线程)从main方法开始的,
一直执行到main方法结束。这个线程在java中称之为主线程。 当主线程在这个程序中执行时,如果遇到了循环而导致停留时间过长,
就无法执行下面的程序。
可不可以实现一个主线程负责执行其中一个循环,由另一个线程负责其他代码的执行。
实现多部分的代码同时执行。
这就是多线程技术可以解决的问题。 该如何创建线程呢? 通过API中的英文Thread搜索。查到了Thread类。
通过阅读Thread类中的描述。
创建线程有两种方式。
1,继承Thread类。
1.1 定义一个类去继承Thread.
1.2 重写run方法。
1.3 创建子类对象。就是创建线程对象。
1.4 调用strat方法。开启线程并让线程执行,同时还会告诉jvm调用run方法。 为什么要这么做?
继承Thread类:因为Thread类描述线程事物,具备线程应该有的功能。
那为什么不直接创建Thread类的对象呢?
Thread t1 = new Thread();
t.strat();//这么做没有错,但是该strat调用的是Thread类中的run方法,
而这个run方法没有做什么事情,更重要的是这个run方法中并没有定义我们需要让
线程执行的代码。 创建线程的目的是什么?是为了建立单独的执行路径,让多部分代码实现同时执行。
也就是线程创建并执行需要给定代码(线程的任务)。
对于之前所讲的主线程,它的任务定义在了主函数中。
自定义的线程需要执行的任务都定义在run方法中。
Thread类中run方法内部的任务并不是我们所需要的。只要重写这个run方法就行了。
既然Thread类已经定义了线程任务的位置,只要在位置中定义任务代码即可。
所以进行了重写run方法动作。 多线程执行时,在栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间。
进行方法的压栈和弹栈。 当执行线程的任务结束了,线程自动在栈内存中释放了。
当所有的执行线程都结束了,进程就结束了。 //获取线程名称。可以通过Thread类中的一个currentThreadd()方法。怎么获取名称呢?
getName(); Thread.currentThread().getName(); 主线程的名称是:main
自定义的线程名称是:Thread-1 线程多个时,数字依次递增。
*/ class Demo extends Thread
{
private String name;
Demo(String name)
{
this.name = name;
}
public void run()
{
//int[] arr = new int[3];
//System.out.println(arr[4]);
for(int x=1;x<=20;x++)
{
System.out.println("name="+name+"....."+Thread.currentThread().getName()+".."+x);
}
}
} class ThreadDemo1
{
public static void main(String[] args)
{
//创建了两个线程对象。
Demo d1 = new Demo("小强");
Demo d2 = new Demo("旺财");
d2.start();//将d2这个线程开启。
d1.run();//由主线程负责。 /*
线程对象调用run方法和调用start方法的区别?
调用run方法不开启线程,仅是对象调用方法。
调用start开启线程,并让jvm调用run方法在开启的线程中执行。
*/
}
}
 //创建线程的第二种方式。
/*
创建线程的第二种方式:使用Runnable接口。
1,定义类实现Runnable接口。//避免了单继承的局限性。
2,覆盖接口中的run方法。将线程任务代码定义到run方法中。
3,创建Thread类的对象。 //只有创建Thread类的对象才可以创建线程。
4,将Runnable接口的子类对象作为参数传递给Thread类的构造函数。
因为线程任务已被封装到Runnable接口的run方法中,而这个run方法所属于Runnable接口的子类对象。
所以将这个子类对象作为参数传递给Thread的构造函数,这样,线程对象创建时就可以明确要运行的任务。
5,调用Thread类的strat方法开启线程。 第二种方式实现Runnable接口避免了单继承的局限性。所以,较为常用。
实现Runnable接口的方式,更加的符合面向对象,线程分为两部分,一部分线程对象,一部分线程任务。
继承Thread类,线程对象和线程任务耦合在一起,一旦创建Thread类的子类对象,既是线程对象,又有线程任务。
实现Runnable接口,将线程任务单独分离出来封装成对象。类型就是Runnable接口类型。
Runnable接口对线程对象和线程任务解耦。 //通过源代码的形式讲解了一些Runnable接口的子类对象作为参数传递给Thread构造函数的原因。
class Thread{
private Runnable target; Thread(Runnable traget)
{
this.target = target;
}
public void run() {
if (target != null) {
target.run();
}
}
public void strat()
{
run();
}
} Demo d = new Demo();//Runnable d = new Demo();
Thread t = new Thread(d);
t.strat();
*/ class Demo implements Runnable
{
private String name;
Demo(String name)
{
this.name = name;
}
//覆盖了接口Runnable的run方法。
public void run()
{
for(int x=1;x<20;x++)
{
System.out.println("name="+name+"....."+Thread.currentThread().getName()+".."+x);
}
}
}
class ThreadDemo2
{
public static void main(String[] args)
{
//创建Runnable子类的对象。注意它并不是线程对象。
Demo d = new Demo("Demo");
//创建Thread类的对象,将Runnable接口的子类对象作为参数传递给Thread类的构造函数。
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t2.start(); System.out.println(Thread.currentThread().getName()+"------>");
}
}
 //多线程的安全问题产生及原因以及解决思路
/*
案例:售票的例子。 售票的动作需要同时执行。所以要使用多线程技术。 发生了线程安全问题,出现了错误的数据;0 -1 -2 问题产生的原因:
1,线程任务在操作共享的数据。
2,线程任务操作共享数据的代码有多条(运算有多个)。 解决思路:
只要让一个线程在执行线程任务时,将多条操作共享数据的代码执行完,
在执行过程中,不要让其他线程参与运算就行了。 代码体现:
Java中解决此问题通过代码块来完成的,
这个代码代码块称之为同步代码块 synchronized
格式:
synchronized(对象)
{
//需要被同步的代码。
} 同步好处:同步代码块解决了多线程安全问题。 同步的弊端:
降低了程序的性能。 同步前提:
必须保证多个线程在同步中使用的是同一个锁
解决了什么问题?当多线程安全问题发生时,加入了同步后,问题依旧发生时,
就要通过这个同步的前提来判断同步是否正确。
*/ class Ticket implements Runnable
{
//1,描述票的数量
private int tickets = 100; //2,售票的动作。这个动作需要被多线程执行,那就是线程任务代码,
//需要定义在run方法中。
//记住,线程任务中通常都有循环结构。
private Object obj = new Object();
public void run()
{
while(true)
{
synchronized(obj)//如果写 new Object() 则用的就不是同一个锁。
{
if(tickets > 0)
{
//要让线程在这里稍停,模拟问题的发生。sleep 看到了 0 -1 -2 这样的错误的数据,这就是传说中的安全问题。
try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/} System.out.println(Thread.currentThread().getName()+"...."+tickets--);//打印线程名称
}
}
}
}
} class ThreadDemo3
{
public static void main(String[] args)
{
//1,创建Runnable接口的子类对象。
Ticket t = new Ticket(); //创建四个线程对象。并将Runnable接口的子类对象作为参数传递给Thread的构造函数。
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
Thread t4 = new Thread(t); //3,开启四个线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}

《day14---多线程入门_进阶》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. OpenCV3编程入门笔记(2)计时函数、感兴趣区域RIO、分离/混合通道

    11     绘制直线的line函数 DrawLine(Mat img, Pont start, Point end); 绘制椭圆的ellipse函数 DrawEllipse(Mat img, dou ...

  2. linux 重命名文件和文件夹

    linux下重命名文件或文件夹的命令mv既可以重命名,又可以移动文件或文件夹. 例子:将目录A重命名为B mv A B 例子:将/a目录移动到/b下,并重命名为c mv /a /b/c 其实在文本模式 ...

  3. centos7 最小化安装 无 ifconfig,netstat 的安装

    centos7 最小化安装 无 ifconfig,netstat 的安装 centos7 最小化安装之后,默认是没有 ifconfig,netstat命令的: 我们可以直接使用 yum -y inst ...

  4. virtualBox虚拟机安装与主机互访和实现上网配置

    1.到官方网下载vitualBox虚拟机,目前最新版本5.0,并安装. https://www.virtualbox.org/ 2.下载安装CentOS系统安装文件 本文采用CentOS-6.5-i3 ...

  5. 128. Longest Consecutive Sequence *HARD* -- 寻找无序数组中最长连续序列的长度

    Given an unsorted array of integers, find the length of the longest consecutive elements sequence. F ...

  6. ios基础篇(七)——UISwich、UISlider、UIProgressView的用法总结

    一.UISlider UIslider滑块控件在IOS开发中会常用到,可用于调节音量,字体大小等UI方面的交互:UISlider实例提供一个控件,让用户通过左右拖动一个滑块(可称其为“缩略图”)来选择 ...

  7. python——使用readline库实现tab自动补全

    Input History readline tracks the input history automatically. There are two different sets of funct ...

  8. 经典SQL语句大全.doc

    1.说明:创建数据库CREATE DATABASE database-name 2.说明:删除数据库drop database dbname3.说明:备份sql server--- 创建 备份数据的 ...

  9. 编写自己的Windows Live Writer插件

    起因 自从小猪使用Windows Live Writer(wlw)来写博客之后就很少打开网站的后台编辑器了,这真是个写博客的好东西啊,但是任何东西都是不完美的.索契冬奥会开幕式都会把五环弄成四环呢!对 ...

  10. uva 10668

    #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> us ...