Java面向对象程序设计第9章1-9
Java面向对象程序设计第9章1-9
1. 线程和进程的联系和区别是什么?
联系:
- 一个进程可以包括多个线程。
区别:
进程: 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,它是系统进行资源分配和调度的一个独立单位。
线程: 线程是进程的一个实体,是CPU调度和分配的基本单位。线程基本不拥有系统资源,与同一个进程的其他线程共享进程中所拥有的所有资源。
2. 什么是前台线程,什么是后台线程?
应用程序必须运行完所有的前台线程才可以退出;而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时都会自动结束。
3. 创建线程有几种方法?它们之间的区别是什么?
第一种方式:直接继承线程Thread类创建对象
1.Thread子类无法再从其它类继承(java语言单继承)。
2.编写简单,run()方法的当前对象就是线程对象,可直接操作。
public MyThread extends Thread{
……
public void run() { 线程体逻辑 }
}
//创建及启动线程:
MyThread t = new MyThread();
t.start();
第二种方式:使用Runnable接口创建线程
1.可以实现多个线程资源共享
2.线程体run()方法所在的类可以从其它类中继承一些有用的属性和方法
public MyThread implements Runnable {
……
public void run() { 线程体逻辑 }
}
//创建及启动线程:
MyThread t = new MyThread();
Thread t1 = new Thread(t);
t1.start();
4.线程的生命周期有哪些状态?哪些方法可以改变这些状态?
- 创建状态:线程对象已经创建,还没有在其上调用start()方法。
- 可运行状态:当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。当start()方法调用时,线程首先进入可运行状态。在线程运行之后或者从阻塞、等待或睡眠状态回来后,也返回到可运行状态。
- 运行状态:线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。
- 阻塞状态:这是线程有资格运行时它所处的状态。如执行了join/sleep/wait方法,会让出CPU,只有当引起阻塞的原因消除时,线程才能转入就绪状态。
- 死亡态:当线程的run()方法完成时就认为它死去。或者抛出一个未捕获到的Exception或Error。
5.什么是线程安全?为什么会产生线程安全问题?如何解决线程安全问题?
线程安全:线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。
原因是由于不同线程获取到资源时进行运算,但未来得及写入时,线程改变,则另外线程读入的资源就是错误,导致所有线程写入读入不同步。
解决办法:
使用监视器,使用关键字synchronized监视同步代码块,当一个线程获得监视权限时,别的线程就无法获得,保证每时每刻只有一个线程调用某一方法
6.什么是线程的同步通信?同步通信又是如何实现的?
线程同步通信是希望实现两个或多个线程之间的某种制约关系
实现:首先是用监视器synchronized来保证每次只有一个线程调用方法,其次引入一个boolean型标志来判断该线程是否执行或wait,两个线程时使用notify(),多个线程时用notifyAll()来让出监视器并唤醒其他线程。这样就实现了线程之间的关系。
//使用wait和notifyAll实现线程间同步通信 (两个存钱线程,一个取钱线程)
class Account{
volatile private int value;
//布尔标志
volatile private boolean isMoney = false;
//put设为同步方法
synchronized void put(int i) {
while(isMoney){
try{ wait();} //线程等待
catch(){Exception e}{}
}
value = value + i;
System.out.println("存入"+i+" 账上金额为:"+value);
isMoney = true;//设置标志
notifyAll(); //唤醒等待资源的所有线程
}
synchronized int get(int i) {//同步方法
while(!isMoney) ){
try { wait();}
catch(){Exception e}{}
}
if (value>i)
value = value - i;
else {
i = value;
value = 0;
}
System.out.println("取走"+i+" 账上金额为:"+value);
isMoney = false;
notifyAll();
return i;
}
}
class Save implements Runnable{
private Account a1;
public Save(Account a1){this.a1 = a1;}
public void run(){
while(true){ a1.put(100);}
}
}
class Fetch implements Runnable {
private Account a1;
public Fetch(Account a1) { this.a1 = a1 ;}
public void run(){
while(true){ a1.get(100);}
}
}
public class TestCommunicate{
public static void main(String[] args){
Account a1 = new Account();
new Thread(new Save(a1)).start(); new Thread(new Save(a1)).start();
new Thread(new Fetch(a1)).start();
}}
7.什么是死锁?
如果多个线程都处于等待状态,彼此需要对方所占用的监视器所有权,
就构成死锁(deadlock),Java即不能发现死锁也不能避免死锁。
方法一:{
synchronized(A) {
….
synchronized(B) {
….
}
}
}
方法二:{
synchronized(B) {
….
synchronized(A) {
….
}
}
}
注意
可能发生死锁的代码执行中不一定会死锁,因为线程之间的执行存
在很大的随机性。
线程方法suspend()、resume()、stop()由于存在引起死锁的可能,
因而逐渐不用(Deprecated)。
8.如何让某个对象的A方法内的一个代码块和另一个方法B实现同步?
class Account
{
volatile private int value;
void put(int i)
{
synchronized(this) {
value = value + i;
System.out.println("存入"+i+" 账上金额为:"+value);
}
}
synchronized int get(int i)
{
if (value>i)
value = value - i;
else
{ i = value;
value = 0;
}
System.out.println("取走"+i+" 账上金额为:"+value);
return i;
}
}
class Save implements Runnable
{
int a=2000;
private Account a1;
public Save(Account a1)
{
this.a1 = a1;
}
public void run()
{
while(a-->0){
a1.put(100);
}
}
}
class Fetch implements Runnable
{
int a=2000;
private Account a1;
public Fetch(Account a1)
{this.a1 = a1 ;}
public void run()
{
while(a-->0){
a1.get(100);
}
}
}
public class Test{
public static void main(String[] args){
Account a1 = new Account();
new Thread(new Save(a1)).start();
new Thread(new Fetch(a1)).start();
}
}
put方法的代码块被监视,get函数被监视,保证了value的正确性,输出结果为存钱取钱的随机顺序, 这里没有设置存取的制约关系。
9.设计一个程序产生两个线程A与B,B线程执行10秒钟后,被A线程中止。
public class test {//如何中断线程?答案是添加一个开关。
private volatile static boolean on = false;
//内部类
public class MyThreadTwo implements Runnable {
@Override
public void run() {
try {
System.out.println("into ---" + Thread.currentThread().getName());
Thread.sleep(10000);//由于等待时间10秒,输出多,上面的into语句被覆盖了
System.out.println("out " + Thread.currentThread().getName());
test.on=true;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void start() {
//一个Thread的构造函数接受一个Runnable参数,而传入的lambda表达式正好符合其run()函数,
// 所以Java编译器推断它为Runnable。
Thread thread1 = new Thread(() -> {
while (!on) {
System.out.println(Thread.currentThread().getName());
}
});
Thread thread2 = new Thread(new MyThreadTwo());
thread1.start();
thread2.start();
}
public static void main(String[] args) {
test test = new test();
test.start();
}
}
10.补充(选做):编写一个基于多线程的生产者/消费者程序,各产生10个生产者和消费者线程,共享一个缓冲区队列(长度自设),生产者线程将产品放入到缓冲区,消费者线程从缓冲区取出产品。
class Cache {
volatile private int value;
final private int productSize;
public Cache(int pro) {
productSize = pro;
}
synchronized void put() {//存
while (value == productSize) {//缓存区产品长度满时等待,不存
try {
wait();//线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
value = value + 1;
System.out.println(Thread.currentThread().getName() + "存了" + 1+", 现value=" + value);
notifyAll();//唤醒等待资源的所有线程
}
synchronized void get() {//取
while (value == 0) {//缓存区产品长度空时等待,不取
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
value = value - 1;
System.out.println(Thread.currentThread().getName() + "取了" + 1+", 现value=" + value);
notifyAll();
}
}
//生产者
class produce implements Runnable {
private Cache a1;
public produce(Cache a1) {
this.a1 = a1;
}
public void run() {
while (true) {
a1.put();
}
}
}
//消费者
class consumer implements Runnable {
private Cache a1;
public consumer(Cache a1) {
this.a1 = a1;
}
public void run() {
while (true) {
a1.get();
}
}
}
public class test{
public static void main(String[] args) {
Cache a1=new Cache(20);
//10个生产者
new Thread(new produce(a1)).start();
new Thread(new produce(a1)).start();
new Thread(new produce(a1)).start();
new Thread(new produce(a1)).start();
new Thread(new produce(a1)).start();
new Thread(new produce(a1)).start();
new Thread(new produce(a1)).start();
new Thread(new produce(a1)).start();
new Thread(new produce(a1)).start();
new Thread(new produce(a1)).start();
//10个消费者
new Thread(new consumer(a1)).start();
new Thread(new consumer(a1)).start();
new Thread(new consumer(a1)).start();
new Thread(new consumer(a1)).start();
new Thread(new consumer(a1)).start();
new Thread(new consumer(a1)).start();
new Thread(new consumer(a1)).start();
new Thread(new consumer(a1)).start();
new Thread(new consumer(a1)).start();
new Thread(new consumer(a1)).start();
}
}
在这里开始对volatile不是很了解其机制,记得老师讲了i--
的操作三条指令,详细了解了下,具体看:
Java面向对象程序设计第9章1-9的更多相关文章
- Java面向对象程序设计第14章3-8和第15章6
Java面向对象程序设计第14章3-8和第15章6 3.完成下面方法中的代码,要求建立一个缓冲区,将字节输入流中的内容转为字符串. import java.io.*; public class tes ...
- Java面向对象程序设计第8章3-5
Java面向对象程序设计第8章3-5 3.String类型有什么特点? 一旦赋值,便不能更改其指向的字符对象 如果更改,则会指向一个新的字符对象 不能为null 4.String什么时候进行值比较,什 ...
- Java面向对象程序设计第7章1-8
Java面向对象程序设计第7章1-8 1."程序中凡是可能出现异常的地方必须进行捕获或拋出",这句话对吗? 不对. 异常分两类,runtime异常和非runtime异常. runt ...
- Java面向对象程序设计第5章1-9
1.面向对象的主要特征是什么? 三大特征是:封装.继承和多态. 封装:是指将某事物的属性和行为包装到对象中,这个对象只对外公布需要公开的属性和行为,而这个公布也是可以有选择性的公布给其它对象. 继承: ...
- Java面向对象程序设计第6章1-12
1.this和super各有几种用法? this this 用法有三种,主要应用场合: 表示当前对象引用,常用于形参或局部变量与类的成员变 量同名的情形,使用this.成员名表示当前对象的成员 表示当 ...
- Java面向对象程序设计第15章5
5. 利用URLConnetction对象编写程序返回某网站的首页,并将首页的内容存放到文件当中. import java.net.*; import java.io.*; public class ...
- 20165220实验二《Java面向对象程序设计》
实验封面: 实验二 面向对象程序设计-1 实验要求: 参考 http://www.cnblogs.com/rocedu/p/6371315.html#SECUNITTEST 参考http://www. ...
- 2017-2018-2 20165301 实验四《Java面向对象程序设计》实验报告
2017-2018-2 20165301 实验四<Java面向对象程序设计>实验报告 一.Android Stuidio的安装测试 实验要求: 参考<Java和Android开发学习 ...
- 2017-2018-2 20165207实验二《Java面向对象程序设计》实验报告
2017-2018-2 20165207实验二<Java面向对象程序设计>实验报告 课程:Java程序设计 班级:1652 姓名:李天林 学号:20165207 实验日期:2018年4月1 ...
随机推荐
- FinalShell for Mac
Mac一键安装脚本 curl -o finalshell_install.sh www.hostbuf.com/downloads/finalshell_install.sh;chmod +x fin ...
- 【NS2】常用资源(转载)
(一). NS常用基本网站 1. 寻求问题答案最好的地方. http://mailman.isi.edu/pipermail/ns-users/ 2. 柯老师的网站,包含很多非常实用资源:安装, ...
- hdu 1561【树形dp+01背包】
http://acm.hdu.edu.cn/showproblem.php?pid=1561 很容易想到如果是要攻克v城需要先攻克u城的话,可以建u到v的边.但是如果能够直接攻克u城呢?无边可建,这样 ...
- @codeforces - 1214H@ Tiles Placement
目录 @description@ @solution@ @part - 1@ @part - 2@ @accepted code@ @details@ @description@ 给定一个 n 点的树 ...
- android service中stub作用是什么?
AIDL(android 接口描述语言)是一个IDL语言,它可以生成一段代码,可以使在一个android设备上运行的两个进程使用内部通信进程进行交互.如果你需要在一个进程中(例如:在一个Activit ...
- POJ1664 放苹果
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int ...
- 洛谷 3177 [HAOI2015] 树上染色
题目描述 有一棵点数为 N 的树,树边有边权.给你一个在 0~ N 之内的正整数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的N-K个点染成白色 . 将所有点染色后,你会获得黑点两两之 ...
- 【原生JS】自动渐变轮播
渐变主要是通过CSS3的动画实现. 只需给css中添加transtion动画时间加上JS设置指定图片透明度显示与消失即可实现渐变过程. 效果图: HTML: <!DOCTYPE html> ...
- 2016年NOIP普及组复赛题解
题目涉及算法: 买铅笔:入门题: 回文日期:枚举: 海港:双指针: 魔法阵:数学推理. 买铅笔 题目链接:https://www.luogu.org/problem/P1909 设至少要买 \(num ...
- <climits>头文件
<climits>头文件定义的符号常量 CHAR_MIN char的最小值SCHAR_MAX signed char 最大值SCHAR_MIN signed char 最小值UCHAR_ ...