多线程 同步异步锁 单列

来源:互联网 发布:淘宝个人主页标签 编辑:程序博客网 时间:2024/05/16 17:06

1. 多线程

1.1Synchronized线程的同步与锁

同一进程中的多个线程,共享同一块内存空间。多个线程访问同一份资源,容易造成访问冲突问题。在Java中,只能通过改进方法,用方法来解决这种冲突问题。

l 把synchronized看做房间的钥匙。

当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

当两个并发线程访问同一个对象object中的这个synchronized同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块,处于阻塞状态。

什么时候使用锁?

多线程同时操作一份数据

注意:Synchronized允许加在方法前,表示方法是线程安全的。

多个代理访问同一份资源,出现资源抢夺的问题,同步 :并发,多个线程访问同一份资源,确保资源安全----线程安全

2种  1.同步块  

synchronized(引用类型/this/类.class){}

2.同步方法

访问修饰符 synchronized 返回值类型  方法名(){}

举例: 同步的使用

package com.njwb.synchronizeduse;

/**

 * 1.同步方法  访问修饰符synchronized 返回值类型   方法名(参数列表){....} ,被同步的方法,一次只允许1个线程执行

 * 2.同步代码块  被同步的代码块,一次只能1个线程执行

 * synchronized(引用数据类型/this/.class(类的模板)){

* }

 * @author Administrator

 *

 */

public class Web12306implements Runnable {

private int ticket = 10;

private boolean flag =true;

@Override

public void run() {

while(flag){

test4();

}

}

/**

 * 版本7: 线程不安全,锁定的对象不正确

 */

public void test7(){

synchronized ((Integer)ticket) {

if(ticket<=0){

flag = false;

return;

}

try {

Thread.sleep(200); //加入网络延迟,放大出错的概率

} catch (InterruptedException e) {

e.printStackTrace();

}

ticket--;

System.out.println(Thread.currentThread().getName()+"抢到了,剩余票数为:"+ticket);

}

}

/**

 * 版本6:线程不安全的 ,同步范围不正确

 */

//a,b,c

public void test6(){

//a,b,c

if(ticket<=0){

flag = false;

return;

}

//a,b,c

synchronized (this) {

try {

Thread.sleep(200); // 加入网络延迟,放大出错的概率

} catch (InterruptedException e) {

e.printStackTrace();

}//a  ,b ,c

ticket--;

System.out.println(Thread.currentThread().getName() +"抢到了,剩余票数为:"

+ ticket);

}//a ,带走了1ticket=0 ,  b带走的0ticket=-1 ,  ticket=-2 c带走的-1

}

/**

 * 版本5:线程不安全,同步范围不正确

 */

//a,b,c

public void test5(){

//a,b,c

synchronized (this) {

if(ticket<=0){

flag = false;

return;

}

}

//a,b,c

try {

Thread.sleep(200); // 加入网络延迟,放大出错的概率

} catch (InterruptedException e) {

e.printStackTrace();

}

ticket--;

System.out.println(Thread.currentThread().getName() +"抢到了,剩余票数为:"

+ ticket);

}//a 带走了1ticket=0,b带走了0ticket=-1,c带走了-1ticket=-2

/**

 * 版本4:线程安全的

 */

public void test4(){

synchronized (Web12306.class) {

if(ticket<=0){

flag = false;

return;

}

try {

Thread.sleep(200); //加入网络延迟,放大出错的概率

} catch (InterruptedException e) {

e.printStackTrace();

}

ticket--;

System.out.println(Thread.currentThread().getName()+"抢到了,剩余票数为:"+ticket);

}

}

/**

 * 版本3: 线程安全的,同步代码块

 */

//a,b,c

public void test3(){

//a,b,c

synchronized (this) {

//a,b,c

if(ticket<=0){

flag = false;

return;

}

//a

try {

Thread.sleep(200); //加入网络延迟,放大出错的概率

} catch (InterruptedException e) {

e.printStackTrace();

}

ticket--;//a

System.out.println(Thread.currentThread().getName()+"抢到了,剩余票数为:"+ticket);

}//a 带走的1  ticket=0 ,b ,c

}

/**

 * 版本2线程安全的 ,同步方法

 */

//a,b,c

public synchronized void test2(){

//a,b,c

if(ticket<=0){

flag = false;

return;

}

//a

try {

Thread.sleep(200); //加入网络延迟,放大出错的概率

} catch (InterruptedException e) {

e.printStackTrace();

}

ticket--;

System.out.println(Thread.currentThread().getName()+"抢到了,剩余票数为:"+ticket);

}//a带走了1,剩余的ticket=0

/**

 * 版本1:线程不安全的

 */

//a,b,c  ticket=1

public void test(){

//a,b,c

if(ticket<=0){

flag = false;

return;

}

//a,b,c

try {

Thread.sleep(200); //加入网络延迟,放大出错的概率

} catch (InterruptedException e) {

e.printStackTrace();

}

ticket--;

System.out.println(Thread.currentThread().getName()+"抢到了,剩余票数为:"+ticket);

}//a带走1ticekt=0 b带走了0ticekt=-1  c带走的-1ticket=-2

public void stop(){

flag = false;

}

}

package com.njwb.synchronizeduse;

public class SynDemo01 {

public static void main(String[] args) {

Web12306 we = new Web12306();

Thread th1 = new Thread(we,"黄牛甲");

Thread th2 = new Thread(we,"黄牛乙");

Thread th3 = new Thread(we,"黄牛丙");

th1.start();

th2.start();

th3.start();

}

}

1.2单例设计模式

1.2.1懒汉式单例

l 只支持单线程情况的最简单的懒汉式单例

package com.njwb.singletonmodel;

/**

 * 懒汉式单例:1.构造器私有化,避免外部直接创建

 * 2.声明一个私有的静态变量

 * 3.声明一个公有的静态方法,返回该变量的值,如果该变量不存在,则创建

 * 最简单的单例,只在单线程情况下,线程安全的,如果在多线程情况下,线程不安全的

 *

 */

public class Jvm {

//instance在静态方法中使用,所以必须用static修饰

private static  Jvminstance = null;

private Jvm() {

}

//因为类名来访问,Jvm的对象不能再其他地方去new,不能通过对象名.方法名访问,只能通过类名.方法

public static Jvm getInstance(){

if(null==instance){

instance = new Jvm();

}

return instance;

}

}

支持多线程情况的懒汉式单例  加入网络延迟的情况处理

package com.njwb.singletonmodel2;

/**

 * 懒汉式单例:1.构造器私有化,避免外部直接创建

 * 2.声明一个私有的静态变量

 * 3.声明一个公有的静态方法,返回该变量的值,如果该变量不存在,则创建

 * 最简单的单例,只在单线程情况下,线程安全的,如果在多线程情况下,线程不安全的

 * 静态方法中不能出现this,super

 *

 */

public class Jvm {

//instance在静态方法中使用,所以必须用static修饰

private static  Jvminstance = null;

private Jvm() {

}

/**

 * 版本4:线程安全的,提高效率  double checking

 * @param time

 * @return

 */

//a,b,  c,d,e

public static Jvm getInstance(long time){

//a,b,c,d,e

if(null==instance){//提高已经存在对象的 效率(instance对象已经创建的情况下,有其他线程过来,不需要等待,直接return)

//a,b

synchronized (Jvm.class) {

//a,b

if(null==instance){  //线程安全

try {

Thread.sleep(time);

} catch (InterruptedException e) {

e.printStackTrace();

}//a

instance = new Jvm();

}

}

}

return instance;//a,b ,c,d,e

}

/**

 * 版本3:线程安全的,同步代码块,效率不高

 * @param time

 * @return

 */

//a,b,c,d,e

public static Jvm getInstance3(long time){

//a,b,c,d,e

synchronized (Jvm.class) {

//a,b ,c

if(null==instance){

try {

Thread.sleep(time);

} catch (InterruptedException e) {

e.printStackTrace();

}//a

instance = new Jvm();

}

}

return instance;//a ,b,c

}

/**

 * 版本2:同步方法,线程安全的

 * @param time

 * @return

 */

//a,b

public synchronized static Jvm getInstance2(long time){

//a,b

if(null==instance){

try {

Thread.sleep(time);

} catch (InterruptedException e) {

e.printStackTrace();

}//a

instance = new Jvm();

}

return instance;

}//a,b

/**

 * 版本1:线程不安全的

 * @param time

 * @return

 */

//a,b

public static Jvm getInstance1(long time){

//a,b

if(null==instance){

//a,b

try {

Thread.sleep(time);

} catch (InterruptedException e) {

e.printStackTrace();

}

instance = new Jvm();//a,b

}

return instance;//a ,b

}

}

package com.njwb.singletonmodel2;

 

public class JvmThreadextends Thread {

private long time;

public JvmThread(long time) {

super();

this.time =time;

}

 

@Override

public void run() {

System.out.println(Thread.currentThread().getName()+"创建了--->"+Jvm.getInstance(time));

}

}

package com.njwb.singletonmodel2;

/**

 * jt1,jt2 2个线程同时访问的时,仍旧要保证内存地址一样,也就是访问同一个对象

 * @author Administrator

 *

 */

public class SynDemo2 {

public static void main(String[]args) {

JvmThread jt1 = new JvmThread(200);

JvmThread jt2 = new JvmThread(500);

jt1.start();

jt2.start();

}

}

支持多线程情况的懒汉式单例

package com.njwb.singletonmodel2;

/**

 * 懒汉式单例:1.构造器私有化,避免外部直接创建

 * 2.声明一个私有的静态变量

 * 3.声明一个公有的静态方法,返回该变量的值,如果该变量不存在,则创建

 * 最简单的单例,只在单线程情况下,线程安全的,如果在多线程情况下,线程不安全的

 * @author Administrator

 *

 */

public class MyJvm {

private static MyJvminstance;

private MyJvm(){

}

public synchronized static MyJvm getInstance(){

if(null==instance){

instance = new MyJvm();

}

return instance;

}

public static MyJvm getInstance2(){

synchronized (MyJvm.class) {

if(null==instance){

instance = new MyJvm();

}

}

return instance;

}

/**

 * double checking  效率好

 * @return

 */

public static MyJvm getInstance3(){

if(null==instance){

synchronized (MyJvm.class) {

if(null==instance){

instance = new MyJvm();

}

}

}

return instance;

}

}

1.2.2饿汉式单例

饿汉式单例的方式1(最常见):

package com.njwb.singletonmodel2;

/**

 * 饿汉式单例:1.构造器私有化,避免外部直接创建

 * 2.声明1个私有的静态变量,并创建该变量

 * 3.声明1个公有的静态方法,返回该变量的值

 * 天生线程安全的

 * @author Administrator

 *

 */

public class MyJvm2 {

//instanceMyJvm2类加载的时候,就会被加载

private static MyJvm2instance = new MyJvm2();

private MyJvm2(){

}

public static MyJvm2 getInstance(){

return instance;

}

}

饿汉式单例的方式2:

package com.njwb.singletonmodel2;

/**

 * 饿汉式单例:版本2   

 * @author Administrator

 *

 */

public class MyJvm3 {

//延缓了JvmHolder的加载时间,只有你调用了getInstance方法,JvmHolder才会被加载,instance才会new

private static class JvmHolder{

private static MyJvm3instance = new MyJvm3();

}

private MyJvm3(){

}

public static MyJvm3 getInstance(){

return JvmHolder.instance;

}

}

1.3生产者消费者

练习

写一个线程(Producer“生产者”,每隔1秒往LinkedList中加入一个商品

package com.njwb.producer;

import java.util.LinkedList;

/**

 * 写一个线程(Producer生产者,每隔1秒往LinkedList中加入一个商品

 * @author Administrator

 *

 */

public class Producerimplements Runnable {

private LinkedList<Goods>list = new LinkedList<Goods>();

@Override

public void run() {

while(true){

Goods goods = new Goods();

goods.setGoodsName("键盘");

goods.setPrice(30.2);

goods.setNo((int)(Math.random()*1000));

list.add(goods);

System.out.println("生产了"+goods.getGoodsName()+",编号为:"+goods.getNo());

try {

Thread.sleep(200);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

写一个线程(Consumer) “消费者”,每隔1秒从LinkedList中取出一个商品,removeFirst()

package com.njwb.producer;

import java.util.LinkedList;

/**

 * 写一个线程(Consumer消费者,每隔1秒从LinkedList中取出一个商品,removeFirst(),remove(0)

 * @author Administrator

 *

 */

public class Consumerimplements Runnable  {

private LinkedList<Goods>list = new LinkedList<Goods>();

@Override

public void run() {

while(true){

//消费商品,从集合中删除

Goods goods = list.removeFirst();

System.out.println("消费了"+goods.getGoodsName()+",编号为:"+goods.getNo());

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

package com.njwb.producer;

/**

 * Exception in thread "消费者" java.util.NoSuchElementException

 * 这个时候Consumer线程中的LinkedList自始至终没有任何元素可以消费,Producer中的LinkedList没有关系,属于2

 * 不同的线程的

 * @author Administrator

 *

 */

public class TestProducer {

public static void main(String[] args) {

Producer pro = new Producer();

Consumer con = new Consumer();

new Thread(pro,"生产者").start();

new Thread(con,"消费者").start();

}

}

如何让两个线程共享LinkedList中的数据?

创建一个类“工厂”,把生产和消费移动到工厂中。

package com.njwb.producer2;

import java.util.LinkedList;

public class Factory {

private LinkedList<Goods>list = new LinkedList<Goods>();

/**

 * 生产的方法

 */

public void produce(){

Goods goods = new Goods();

goods.setGoodsName("键盘");

goods.setPrice(30.2);

goods.setNo((int)(Math.random()*1000));

list.add(goods);

System.out.println("生产了"+goods.getGoodsName()+",编号为:"+goods.getNo());

try {

Thread.sleep(200);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

/**

 * 消费的方法

 */

public void consume(){

//消费商品,从集合中删除

Goods goods = list.removeFirst();

System.out.println("消费了"+goods.getGoodsName()+",编号为:"+goods.getNo());

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

package com.njwb.producer2;

 

/**

 * 写一个线程(Producer生产者,每隔1秒往LinkedList中加入一个商品

 * @author Administrator

 *

 */

public class Producerimplements Runnable {

private Factory fac;

public Producer(Factory fac) {

super();

this.fac = fac;

}

 

@Override

public void run() {

for(int i=0;i<10;i++){

fac.produce();

}

}

}

package com.njwb.producer2;

 

 

/**

 * 写一个线程(Consumer消费者,每隔1秒从LinkedList中取出一个商品,removeFirst(),remove(0)

 * @author Administrator

 *

 */

public class Consumerimplements Runnable  {

private Factory fac;

public Consumer(Factory fac) {

super();

this.fac = fac;

}

 

@Override

public void run() {

for(int i=0;i<10;i++){

fac.consume();

}

}

}

package com.njwb.producer2;

/**

 * Exception in thread "消费者" java.util.NoSuchElementException

 * 虽然这个时候,生产者,消费者共享同一份资源,同一个工厂对象既给了生产者线程,又给了消费者线程,工厂中的有LinkedList存储,删除数据

 * 可是发现事实不如预想,因为生产者线程还没来得及生产,消费者就想去消费,仍旧会有异常出现

 * @author Administrator

 *

 */

public class TestProducer {

public static void main(String[] args) {

//创建1个工厂对象,同一份资源

Factory fac = new Factory();

//2个线程

Producer pro = new Producer(fac);

Consumer con = new Consumer(fac);

Thread th1 = new Thread(pro,"生产者");

Thread th2 = new Thread(con,"消费者");

//这个时候尝试了可以改变2个线程的优先级,让生产者线程获取cpu调度的机会变大,发现仍旧不能解决问题

//th1.setPriority(10);

//th2.setPriority(1);

th1.start();

th2.start();

}

}

1.4Wait和notify

Java提供了3个方法可以实现线程之间的通信:

wait()方法:调用wait()方法,会挂起当前线程,并释放共享资源的锁.

notify()方法:调用了任意对象的notify()方法会在因调用该对象的wait()方法而阻塞的线程中随机选择一个解除阻塞,但要等到获得锁后才可真正执行。

notifyAll()方法:调用了notifyAll()方法会将因调用该对象的wait()方法而阻塞的所有线程一次性全部解除阻塞。

wait(),notify(),和notifyall()这3个方法都是Object类中的final方法,被所有的类继承且不允许重写。3个方法只能在同步方法或同步代码块中使用,否则会抛出异常

package com.njwb.producer2;

import java.util.LinkedList;

public class Factory {

private LinkedList<Goods>list = new LinkedList<Goods>();

/**

 * 生产的方法

 */

public synchronized  void produce(){

if(isFull()){

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

Goods goods = new Goods();

goods.setGoodsName("键盘");

goods.setPrice(30.2);

goods.setNo((int)(Math.random()*1000));

list.add(goods);

System.out.println("生产了"+goods.getGoodsName()+",编号为:"+goods.getNo());

try {

Thread.sleep(200);

} catch (InterruptedException e) {

e.printStackTrace();

}

//生产完成,通知消费

//this.notify();

this.notifyAll();

}

/**

 * 判断集合容量(容量的限值是自己设定的)是否满了,如果满了,返回true

 * @return

 */

public synchronized boolean isFull(){

if(list.size()==2){

return true;

}

return false;

}

/**

 * 判断集合是否为空,如果为空返回true

 * @return

 */

public synchronized boolean isEmpty(){

if(list.size()==0){

return true;

}

return false;

}

/**

 * 消费的方法

 */

public synchronized void consume(){

if(isEmpty()){

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

} //挂起消费线程

}

//消费商品,从集合中删除

Goods goods = list.removeFirst();

System.out.println("消费了"+goods.getGoodsName()+",编号为:"+goods.getNo());

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

//消费完成,通知生产

this.notify();

}

}

信号灯法: flag 标志位 控制生产线程和消费线程的挂起或者执行  , true 生产者生产,消费者等待,生产完成通知消费 ,false 消费者消费,生产者等待,消费完成通知生产

电影类: Movie 类  看成Factory类  ,同一份资源  ,生产者Producer  Player放映者   ,消费者Consumer  Watcher观看者, 生产一部,观看一部

package com.njwb.producer3;

/**

 * 同一份资源 Factory 工厂类的角色 (生产,消费都移到工厂里做)

 * flag  True 生产者生产,消费者等待  ,生产完成后,通知消费

 *       false  消费者消费,生产者等待,消费完成后,通知生产

 *  wait 挂起自身的线程,不会锁住共享资源,其他的线程仍旧可以访问共享资源,挂起的线程何时能够进入就绪状态呢(何时能被唤醒),接收到notify()就可以  

 *  wait,notify,notifyAll 必须在同步方法中(同步代码块中)被使用   

 * @author Administrator

 *

 */

public class Movie {

private String movieName; //电影名字

private boolean flag=true;//标志位 ,刚开始没有资源,无法观看无法消费才行true,消费者就需要等待

/**

 * 生产的方法

 */

public synchronized void play(String name){

if(!flag){// !flag 等价于 flag==false

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

try {

Thread.sleep(300);

} catch (InterruptedException e) {

e.printStackTrace();

}

//电影的名称从外部传入,赋值给当前类的属性movieName

this.movieName = name;

System.out.println("生产了:"+this.movieName);

//停止生产

flag =false;

//生产完成,通知消费

this.notify();

}

/**

 * 消费的方法

 */

public synchronized void watch(){

if(flag){

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

try {

Thread.sleep(200);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("观看了:"+this.movieName);

//更改标志位,停止消费

flag = true;

this.notify();

}

}

package com.njwb.producer3;

/**

 * 生产者

 * @author Administrator

 *

 */

public class Playerimplements Runnable{

private Movie m;

public Player(Movie m) {

super();

this.m = m;

}

@Override

public void run() {

for(int i=0;i<10;i++){

if(i%2==0){

m.play("喜羊羊");

}else{

m.play("灰太狼");

}

}

}

}

package com.njwb.producer3;

/**

 * 消费者

 * @author Administrator

 *

 */

public class Watcherimplements Runnable{

private Movie m;

 

public Watcher(Movie m) {

super();

this.m = m;

}

@Override

public void run() {

for(int i=0;i<10;i++){

m.watch();

}

}

}

package com.njwb.producer3;

public class TestMovie {

public static void main(String[] args) {

//同一份资源

Movie m = new Movie();

//生产者,消费者

Player p = new Player(m);

Watcher w = new Watcher(m);

//开启

new Thread (p,"生产者").start();

new Thread(w,"消费者").start();

}

}

1.5死锁

package com.njwb.synchronizeduse02;

/**

 * 过多的同步容易造成死锁 ,同步的范围太大,效率低,同步的范围太小的,可能线程不安全

 * @author Administrator

 *

 */

public class Buyerimplements Runnable {

private Object money;

private Object goods;

public Buyer(Object money, Object goods) {

super();

this.money = money;

this.goods = goods;

}

@Override

public void run() {

while(true){

test();

}

}

public void test(){

synchronized (goods) {

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (money) {

}

}

System.out.println("一手给货一手给钱");

}

}

 

package com.njwb.synchronizeduse02;

public class Sellerimplements Runnable{

private Object money;

private Object goods;

public Seller(Object money, Object goods) {

super();

this.money = money;

this.goods = goods;

}

 

@Override

public void run() {

while(true){

test();

}

}

public void test(){

synchronized (money) {

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (goods) {

}

}

System.out.println("一手给钱一手给货");

}

}

package com.njwb.synchronizeduse02;

public class Test01 {

public static void main(String[] args) {

//同一份资源

Object goods = new Object();

Object money = new Object();

Buyer buy = new Buyer(money,goods);

Seller sel = new Seller(money,goods);

new Thread (buy,"买家").start();

new Thread(sel,"卖家").start();

}

}

1.6判断字符串是否为空

package com.njwb.util;

/**

 * 饿汉式单例:

 *  必须会

 * @author Administrator

 *

 */

public class StringUtil {

private static StringUtilinstance = new StringUtil();

private StringUtil(){

}

public static StringUtil getInstance(){

return instance;

}

/**

 * 该方法判断输入的字符串是否为空,如果为空,返回true

 * @param str

 * @return

 */

public boolean isEmpty(String str){

if(str==null ||str.trim().equals("")){

return true;

}

return false;

}

}

package com.njwb.util;

/**

 * 必须会

 * @author Administrator

 *

 */

public class StringUtil2 {

public static boolean isEmpty(String str){

if(str==null ||str.trim().equals("")){

return true;

}

return false;

}

}

package com.njwb.util;

import java.util.Scanner;

/**

 * 两种方式:

 * StringUtil 判断字符串是否相等,用到饿汉式单例,每次调用的时候,需要用对象名.方法名,如何获取对象StringUtil.getInstance()

 *  StringUtil.getInstance().isEmpty(要判断的字符串)

 * StringUtil2 判断字符串是否相等,提供1个静态方法,调用的时候 直接类名.方法名StringUtil2.isEmpty(要判断字符串)

 * 单例在用的时候,获取的对象,如果是在同一个.java文件中,不管获取多少个对象,内存地址永远相同,如果不同的.java文件,获取的内存地址

 * 不一定相同

 * @author Administrator

 *

 */

public class TestStringUtil {

public static void main(String[] args) {

Scanner input = new Scanner(System.in);

System.out.println("请输入一个字符串:");

String str = input.nextLine();

//Stringstr = null;

//获取StringUtil类的对象

StringUtil su = StringUtil.getInstance();

System.out.println("su="+su);

//用对象名.方法名

if(su.isEmpty(str)){

System.out.println("字符串为空");

}else{

System.out.println("字符串不为空");

}

/*StringUtil su2 = StringUtil.getInstance();

System.out.println(su2);

StringUtil su3 = StringUtil.getInstance();

System.out.println(su3);*/

//获取StringUtil类的对象

//用对象名.方法名

/*if(StringUtil.getInstance().isEmpty(str)){

System.out.println("字符串为空");

}else{

System.out.println("字符串不为空");

}*/

}

}

 

1.7练习

(1) 在控制台输入两个目录的名称,回车后使用代码完成目录拷贝。

请输入两个目录的名称,用逗号分隔:Parent,Parent2

 

1.8作业

(1) 【基础】以20160419为模版,遍历该目录下所有同学的名字存入一个集合中(可以遍历保存到文件中)。遍历当天作业20160501文件夹,把目录下所有同学的名字存入一个集合中。比较两个集合,输出所有当天没有交作业的同学的名称。(把没交作业的同学的名字存到“没交作业的同学.txt”)

(2) 【可选】在作业1的基础上,判断文件夹下的文件数量,如果小于3个文件,也算没完成。

(3) 【可选】统计作业下文件的大小总,如果没有达到1k,也算没完成。